diff --git a/behaviors.md b/behaviors.md index 0fae9a8..40deccf 100644 --- a/behaviors.md +++ b/behaviors.md @@ -1,15 +1,18 @@ # Behaviors - + +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. + + ## 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 { @@ -60,7 +63,7 @@ class ComAcmeControllerBehaviorBarable extends KControllerBehaviorAbstract } } ``` -And an example controller that registers that behavior. +**_the controller_** ```php class ComAcmeControllerFoo extends KControllerModel { @@ -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 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): @@ -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. diff --git a/behaviors/controller-behaviors.md b/behaviors/controller-behaviors.md index e50a1f3..91fefbf 100644 --- a/behaviors/controller-behaviors.md +++ b/behaviors/controller-behaviors.md @@ -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 @@ -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. diff --git a/behaviors/database-behaviors.md b/behaviors/database-behaviors.md index 8f0275d..44e1f72 100644 --- a/behaviors/database-behaviors.md +++ b/behaviors/database-behaviors.md @@ -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. diff --git a/behaviors/model-behaviors.md b/behaviors/model-behaviors.md index e98d983..ab89efd 100644 --- a/behaviors/model-behaviors.md +++ b/behaviors/model-behaviors.md @@ -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 @@ -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. diff --git a/behaviors/view-behaviors.md b/behaviors/view-behaviors.md index 70c748a..ef7e2f3 100644 --- a/behaviors/view-behaviors.md +++ b/behaviors/view-behaviors.md @@ -1,8 +1,15 @@ - # View Behaviors -There is one major action in the view and that's the `render` method. Consequently, we get an opportunity to affect change in the data before it gets rendered into a view, or change output after that rendering. +There is one major action in the view and that's the `render` method. Consequently, we get an opportunity to affect change in the data before it gets rendered into a view, or change output after that rendering. For example: + +```php +class ComAcmeViewBehaviorBarable extends KViewBehaviorAbstract +{ + function _beforeRender($context){...} + function _afterRender($context){...} +} +``` There are no view behaviors included in the Framework, but that doesn't mean that they aren't useful. Here are some potential example uses: + change the template of a view due to a model state @@ -11,4 +18,9 @@ There are no view behaviors included in the Framework, but that doesn't mean tha + changing the template engine from [`koowa` to `mustache`, `markdown` or `twig`](https://github.com/nooku/nooku-framework/tree/master/code/libraries/koowa/libraries/template/engine) to complile some output, and then switching back to render the rest + effecting the schema used in CSV or JSON return. -Maybe you can think of more. If you do, the pattern for creating and adding a behavior to a view is the same as for the other types in this section. Simply make a new directory in your component's view folder called `behavior` and place your code there. After that, make sure you've added the name of the behavior to the `$config` variable in your view's `_initialize` method. +Maybe you can think of more. If you do, the pattern for creating and adding a behavior to a view is the same as for the other types in this section: + +1. Simply make a new directory in your component called `./view/behavior`. +2. Place your class there, making sure it extends [`KViewBehaviorAbstract`](https://github.com/nooku/nooku-framework/blob/master/code/libraries/koowa/libraries/view/behavior/abstract.php), and follows the proper naming con. +3. You can then define `_beforeRender` or `_afterRender`, or mix in some needed functionality. +4. Make sure you've added the name of the behavior to the `$config` variable in your view's `_initialize` method.