Skip to content
This repository has been archived by the owner on Jun 24, 2020. It is now read-only.

Commit

Permalink
#13 - finishing off major sections
Browse files Browse the repository at this point in the history
  • Loading branch information
Cameron Barr committed Apr 13, 2015
1 parent 7fc36e8 commit f80ae9f
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 44 deletions.
67 changes: 40 additions & 27 deletions behaviors.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
# Behaviors

<!--
The Framework encourages us to follow DRY by giving us tools to encapsulate different strategies, and then compose those pieces together. It provides substantial architecture and convention to us to support this, and the Behavior API is a useful end result.

Behaviors are a key element to being able to design and produce components quickly because they eliminate the need to write that code again. They are leveraged in the Dispatcher, Model, View, Contrller and Database implementations of the Framework, and are available for you to use or extend.
-->
Behaviors are a key element to being able to design and produce components quickly because they help us to isolate a specific area of concern into one class, and eliminate the need to write that code again. They are leveraged in the Dispatcher, Model, View, Controller and Database implementations of the Framework, and are available for you to use or extend.

The hardest part about using them is just learning a little about what they do, and then getting comfortable with their usage. The sections that follow are meant to shed some light on the areas of use and their general make up.

<!-- toc -->

## Example

Here is a trivial example of a Controller behavior so we can refer to some of the concepts involved.
So we can refer to some of the concepts involved, here is an example of a Controller behavior, followed by an example controller that registers that behavior.

**_the behavior_**
```php
class ComAcmeControllerBehaviorBarable extends KControllerBehaviorAbstract
{
Expand Down Expand Up @@ -60,7 +63,7 @@ class ComAcmeControllerBehaviorBarable extends KControllerBehaviorAbstract
}
}
```
And an example controller that registers that behavior.
**_the controller_**
```php
class ComAcmeControllerFoo extends KControllerModel
{
Expand All @@ -77,18 +80,14 @@ class ComAcmeControllerFoo extends KControllerModel

## Background

Behaviors are strategies for customization that let you affect two areas in an object that uses them. They let you:
Behaviors <!--are strategies for customization that--> let you affect two areas in an object that uses them. Namely, they let you:

1. control the input before and the output after the execution of the `_action` methods of a class.
2. add methods to an object's interface

The result of these two abilities is that you have complete control over the end result of the business logic of an object; and can mixin needed functionality into an object at runtime, respectively.
The result of these two abilities is that you have complete control over the end result of the business logic of an object; and can mixin needed functionality into an object at run-time, respectively.

## Controlling the Input and Output

A behavior is an implementation of the `KCommandCallback` class and is part of the Framework's Command Chain API. When a command is invoked, its command callback queue is processed in the order of the priority. The behaviors that are registered with an object sit in this command chain, and the methods that match up with the invoked command are run as a result of invocation.

### Invocation
## Invocation

To show how the processing of a command queue gets started, here is a stripped down version of the [`KViewAbstract::render()`](https://github.com/nooku/nooku-framework/blob/master/code/libraries/koowa/libraries/view/abstract.php#L113):

Expand All @@ -114,37 +113,51 @@ Its always the same general logic:

> Some other examples of the same process can be seen in [`KControllerAbstract::execute()`](https://github.com/nooku/nooku-framework/blob/master/code/libraries/koowa/libraries/controller/abstract.php#L125) and [`KModelAbstract::fetch()`](https://github.com/nooku/nooku-framework/blob/master/code/libraries/koowa/libraries/model/abstract.php#L125).
If the behavior has methods that match the invoked commands, namely `_before[Action]` and `_after[Action]`, they are executed. You can see this method pattern in our [`ComAcmeControllerBehaviorBar`](#example) example behavior above.
If the behavior has methods that match the invoked commands, namely `_before[Action]` and `_after[Action]`, they are executed. You can see this method naming convention in our [`ComAcmeControllerBehaviorBar`](#example) example behavior above.

Its in these methods that we get a chance to change the result of the execution of actions in an object.

## Mixins
>**Technical Tip:** A behavior is an implementation of the `KCommandCallback` class, which is part of the Framework's Command Chain API. When a command is invoked, its command callback queue is processed in the order of the priority. The behaviors that are registered with an object sit in this command chain, and the methods that match up with the invoked command are run as a result of invocation.
## KBehaviorMixin: Behavior Management

For an object to make use of behaviors it needs the interface to manage, and invoke them. There needs to be getters and setters and maybe some way to check if a behavior exists in relation to the object. To get that interface into an object it can conveniently **mixin** the [`KBehaviorMixin`](https://github.com/nooku/nooku-framework/blob/master/code/libraries/koowa/libraries/behavior/mixin/mixin.php#L19) class at construction. For example, you will see something similar to the following in every abstract class where that object type will use behaviors:

```php
public function __construct( KObjectConfig $config)
{
parent::__construct($config);
// Mixin the behavior (and command) interface
$this->mixin('lib:behavior.mixin', $config);
}
```

With that instruction to `mixin('lib:behavior.mixin', $config);` all the methods that our object needs to work with behaviors get added to that object's interface. There is a little more though: [`KBehaviorMixin`](https://github.com/nooku/nooku-framework/blob/master/code/libraries/koowa/libraries/behavior/mixin/mixin.php#L19) extends [`KCommandMixin`](https://github.com/nooku/nooku-framework/blob/master/code/libraries/koowa/libraries/command/mixin/mixin.php), and that class also adds the methods needed to `invokeCommand` as we highlight above.


> [Read more complete Topical Guide on the Mixin](../essentials/mixin.md)
## KBehaviorAbstract

### KBehaviorAbstract
At the heart of the Behavior API is the Mixin. All behaviors are extensions of the [`KObjectMixinAbstract`](https://github.com/nooku/nooku-framework/blob/master/code/libraries/koowa/libraries/object/mixin/abstract.php#L19), and its this class that lets us add a behavior's `public` methods to an object interface, and thus mimic mulitple inheritance.

At the heart of the Behavior API is the Mixin. All behaviors are extensions of the `KObjectMixinAbstract`, and its this fact that lets us add a behavior's `public` methods to an object interface.
> For more information read [the Mixin](../essentials/mixin.md) section
Our [example behavior](#example) above exposes one `public` method called `sendBarNotifiation()`. If we create an instance of `ComAcmeControllerFoo`, e.g.:

Our example exposes one `public` method called `sendBarNotifiation()`. If we create a controller with ComAcmeControllerBehaviorBarable registered as a behavior, e.g.
```php
$controller = KObjectManager::getInstance()
->getObject('com://site/acme.controller.foo');
```
then we can call `$controller->sendBarNoticiation();`, even though its not defined in the `ComAcmeControllerFoo` class.

### KBehaviorMixin: Behavior Management

For an object to make use of behaviors it needs the interface to manage them. There needs to be getters and setters and maybe some way to check if a behavior exists in relation to the object. To get that interface into an object it can conveniently **mixin** the `KBehaviorMixin` class at construction. For example, you will see something similar to the following in every abstract class where that object type will use behaviors:
We can call that method even though its not defined in the `ComAcmeControllerFoo` class:

```php
public function __construct( KObjectConfig $config)
if($controller->isBarable())
{
parent::__construct($config);
// Mixin the behavior (and command) interface
$this->mixin('lib:behavior.mixin', $config);
$controller->sendBarNoticiation();
}
```
The `isBarable` method call does two things for us: it checks to see if the object has the `barable` behavior, and if it does, will make sure that behavior's mixable methods are in fact mixed in to the object interface.

With that instruction to `mixin('lib:behavior.mixin', $config);` all the methods that our object needs to work with behaviors get added to that object's interface. There is a little more though: `KBehaviorMixin` extends `KCommandMixin`, and that class also adds the methods needed to `invokeCommand` as we highlight above.
## What's Next

In the sections that follow we cover each major layer in the Framework that makes use of behaviors, and attempt re-enforce some of the concepts that we've covered here.
8 changes: 4 additions & 4 deletions behaviors/controller-behaviors.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@

The Framework controller package does a great job with handling the standard `browse`, `read`, `edit`, `add` and `delete` (BREAD) requests and the action of rendering of results of those requests where there is one. Each of those actions are exposed to before and after command chains, and we use a number of behaviors out of the box to augment Controller functionality and interface.

As with all behaviors we've discussed, they allow us to separate out standardized ontroller logic and compose those pieces of logic into a queue to be run in succession. Again, they can also add methods to our controller interface allowing us to expose new, more specific controller actions.
As with all behaviors we've discussed, they allow us to separate out specialized controller logic and compose those pieces of logic into a queue to be run in succession. Again, they can also add methods to our controller interface allowing us to expose new, more specific controller actions.

## Example

A good example of adding new actions to a controller can be seen by looking at the [`Editable`](https://github.com/nooku/nooku-framework/blob/master/code/libraries/koowa/libraries/controller/behavior/editable.php#L16) behavior. It defines three new actions that help dictate the user's flow through the act of editing a record in your component.

When in use, an authorized user can `apply` changes to the record. This initiates a write request, but keeps them on the editing page. If they `save` a record, the same write request gets initiated, but they are redrected to the location they were just before they requested the editing page. Lastly, if they `cancel` they are just redirected to their previous location in the application.
When in use, an authorized user can **apply** (`_actionApply($context)`) changes to the record. This initiates a write request, but keeps them on the editing page. If they **save** (`_actionSave($context)`) a record, the same write request gets initiated, but they are redirected to the location they were just before they requested the editing page. Lastly, if they **cancel** (`_actionCancel($context)`) they are just redirected to their previous location in the application.

Imagine trying to fit this class into a set of controllers by inheritance, but include other pieces of functionality from other classes into that hierarchy.

Adding a behavior to a controller is easy, simply add the `name` to the `behaviors` setting in the form of an array:
Adding a behavior to a controller is easy, simply add the `name` to the `behaviors` property of the `$config` variable in the controller's `_initialize` method:

```php
class ComAcmeControllerBar extends KControllerModel
Expand All @@ -36,7 +36,7 @@ If you wanted to write a new behavior for your component, simply place it in a n

Also, make sure that it extends, directly or indirectly, from [`KControllerBehaviorAbstract`](https://github.com/nooku/nooku-framework/blob/master/code/libraries/koowa/libraries/controller/behavior/abstract.php#L16).

## The Complete List of Controller Behaviors
## The List

There is a lot of work done for you out of the box, and you should take the time to play with each of these structures. Doing so will let you write (or not have to write) the controller layer of your application much more quickly.

Expand Down
16 changes: 8 additions & 8 deletions behaviors/database-behaviors.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
# Database Behaviors

Utilizing database behaviors lets us create [Trigger](http://en.wikipedia.org/wiki/Database_trigger) like procedures in our applications, without having to store them with the database. They provide a means to contextually affect change both before and after `select`, `insert`, `update` and `delete` actions performed in the database layer, specifically in the KDatabaseTableAbstract.
Utilizing database behaviors lets us create [Trigger](http://en.wikipedia.org/wiki/Database_trigger) like procedures in our applications, without having to store them with the database. They provide a means to contextually affect change both before and after `select`, `insert`, `update` and `delete` actions in [`KDatabaseTableAbstract`](https://github.com/nooku/nooku-framework/blob/master/code/libraries/koowa/libraries/database/table/abstract.php).

Behaviors are strategies, and because they are separated out we can use them in many other table objects. Each one extends from `KDatabaseBehaviorAbstract` and thus, `KMixinAbstract`. Because they are [mixins](/essentials/mixin.md) they add methods and functionality to the row level objects (See getAuthor in the [Example](#example) below).
Behaviors are strategies, and because they are separated out we can use them in many other table objects. Each one extends from `KDatabaseBehaviorAbstract` and thus, `KMixinAbstract`. Because they are [mixins](/essentials/mixin.md) they add methods and functionality to the row level objects (See `getAuthor` in the [Example](#example) below).

You can build your own database behaviors in your own applications, or adjust the logic of currently ones to better match your needs by simply extending them.
You can build your own database behaviors in your own applications, or adjust the logic of currently available ones to better match your needs by simply extending them.

If you choose to build new behaviors, simply place them in the `/database/behavior/` folder of your component. To get some inspiration look at some of the [Example](#example) below.
If you choose to build new behaviors, just place them in the `/database/behavior/` folder of your component. To get some inspiration we suggest you check out some of the already available behaviors that we list below.

## Example

One of the easiest examples to understand is the [`KDatabaseBehaviorCreatable`](https://github.com/nooku/nooku-framework/blob/master/code/libraries/koowa/libraries/database/behavior/creatable.php) database behavior. Its purpose is to simply make sure that when we insert a record into a table, it adds the creation date (`created_on`), and the user id number (`created_by`) of the logged in user.
One of the familiar use cases that is already available is the [`KDatabaseBehaviorCreatable`](https://github.com/nooku/nooku-framework/blob/master/code/libraries/koowa/libraries/database/behavior/creatable.php) database behavior. Its purpose is to simply make sure that when we insert a record into a table, it adds the creation date (`created_on`), and the user id number (`created_by`) of the logged in user.

Additionally, the behavior provides a `getAuthor` method to the row object and which grabs the `created_by` of the object and returns a system level user object, so you don't have to for example, get the user id and then create the user object yourself.
For convenience, the behavior provides a `getAuthor` method to the row object. It grabs the `created_by` of the object and returns a system level user object. As a result, you don't have to for example, get the user id and then create the user object yourself.

### Benefits

+ We never have to re-write the code that makes sure that we record those values in another table.
+ There is no question: "Where do we write that code?" In the controller, model or table classes? We are defining these actions at the table level and the logic is cleaner for each of those structures is cleaner.
+ There is no question: "Where do we write that code?" In the controller, model or table classes? We are defining these actions at the table level and the logic is cleaner for each of those structures.
+ It helps promote standardization of column names across tables for this information. In the `creatable` behavior user id is always saved as `created_by` and the date is always stored in `created_on`.

### The Complete List of Database Behaviors
### The List

Let's list all of the framework level behaviors and give some background about each.

Expand Down
4 changes: 2 additions & 2 deletions behaviors/model-behaviors.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The ability to separate out strategies for building queries and models states he

Like all Nooku behaviors, Model behaviors get fired before and after each major action that a model performs: `fetch`, `create`, `count` and `reset`.

Getting to know what the core framework behaviors do is part of the learning curve of using the Framework. The content of the Model `$_state` is coupled to the contents of a request coming down the chain from the dispatcher to the controller. The principal work of the model to take those values which are relevant to it, building queries based on them and then return that result. The model needs to explicitly identify values are relevant to it by `inserting` them into its state. By encapsulating all that work into different behaviors a model definition can become very short:
Getting to know what the core framework behaviors do is part of the learning curve of using the Framework. The content of the Model `$_state` is coupled to the contents of a request coming down the chain from the dispatcher to the controller. The principal work of the model to take those values which are relevant to it; build queries based on them; and then return that result. The model needs to explicitly identify values are relevant to it by `inserting` them into its state. By encapsulating all that work into different behaviors a model definition can become very short:


```php
Expand Down Expand Up @@ -32,7 +32,7 @@ The `Indexable` behavior takes care of finding out what unique indexes you have

This means that for every model that is `Indexable` in our application we don't have to worry about making sure that we've defined unique states in the model or even building queries based on those states, because it is automatic.

## The Complete List of Model Behaviors
## The List

+ [Indexable](https://github.com/nooku/nooku-framework/blob/master/code/libraries/koowa/libraries/model/behavior/indexable.php#L16) Gets the index information from the associated table's schema and populates the state with those columns, and automatically builds the where part of the query based on those states.
+ [Sortable](https://github.com/nooku/nooku-framework/blob/master/code/libraries/koowa/libraries/model/behavior/sortable.php#L16) Adds `sort` and `direction` to the model's state and then builds the `ORDER BY` part of the query object based on those values if they exist.
Expand Down
Loading

0 comments on commit f80ae9f

Please sign in to comment.