Cakephp 2.3: Efficient way to access model properties globally - php

I want to be able to get the names of all models for whom a certain property is a certain value.
Ideally, I'd like to put a property in AppModel that is then inherited and subsequently set by all other models in such a way that it can be easily accessed from anywhere. This is the gist of my idea:
Set this to true in any models I want to group:
class AppModel extends Model {
public $hasPortal = false;
}
Then add this function to AppController:
class AppController extends Controller {
public $components = array('DebugKit.Toolbar');
static function getPortals() {
$portalModels = array();
$models = App::objects('Model');
foreach( $models as $model ) {
if ( !class_exists($model) ) {
$m = ClassRegistry::init($model);
if ( $m->hasPortal ) {
$portalModels[] = $model;
}
}
}
return $portalModels;
}
}
Thus I can do this: $portals = AppController::getPortals() anywhere at all—and it works well enough for now (when I have >20 classes!), but I'm pretty sure it's foolishly inefficient. I want to be able to group collections of models (ideally even controllers and functions) on the fly for generating menus. But I'm quite green with OOP and have a lurking suspicion that this isn't the most efficient way to get the functionality I want.
See the comments before reading on, I'm addressing a request to describe my specific context
I'm not at all confident that this approach makes sense!
The actual thing I'm trying to implement is an automatically created menu in home.ctp. Using the above code, my home.ctp has this:
$portaledModels = AppController::getPortals();
foreach ($portaledModels as $model) {
echo $this->element('modelPortal', array('model' => $model) );
}
(Though eventually $model would be an array that holds descriptions, an icon link, etc.)
It's often the case that, on the default 'home' page of a cake app, all I really want there is a means to navigate to various actions of many models—but not all (ie. entries/index and authors/index are obvious choices, whereas entries_authors has no value to users).
So in this case, I want to create an element that returns a nav interface for those models that should be accessible (this is NOT in lieu of ACL lists, I don't mean to use this for security, just the convenience of automating the content of home.ctp).
I know it's easy to manually create a list of such models and just update it when necessary. In general, though, I try to write nothing by hand that is available programmatically. It occurred to me that I could create a models model, basically a registry of what's in my app, and then requestAction() my way to the same effect. But then I got lost thinking about how to automatically have each model register itself when it's called, but only the first time? This is probably a good time to reaffirm to everyone that I am an amateur developer, hahaha. :)

Related

How to avoid model bloat with eloquent models?

I've been trying to make a small game in Laravel in my spare time and I've been running into trouble with how best to structure the application and issues with certain models getting very bloated.
I'm currently using eloquent models and attaching functionality directly to them. So for example, I have a User model, which started out with the below functions
$user->verify()
$user->creditGold()
$user->debitGold()
which seemed reasonable. As I added functionality to the site, the class started getting bigger and unwieldy though, for example:
$user->creditItem()
$user->debitItem()
$user->equipItem()
$user->unequipItem()
$user->moveToTown()
$user->takeQuest()
$user->ban()
$user->unban()
// etc. etc.
there's a lot of code that feels very unrelated that's been shoved into this one class and it's very messy.
What I've started doing is making helper models that are instantiated and held by the User class. example below
$user->inventory()->creditItem()
$user->inventory()->debitItem()
$user->inventory()->useItem()
It's easy to call and work with but it feels incorrect.
Does anyone have advice for how to best break down a large mass of code that all conceptually belongs to the same entity? I like the idea of functionality being coupled with data because I think that's the most natural way of understanding OO, but would it be better for me to abstract the code out to a Service layer and have service classes that take the user as a parameter and acts on it instead (i.e. $service->giveItemToUser($user, $item) )?
This is where the principle of SoC (Separation of Concerns) becomes very important. What this means is making sure each piece of your app is only concerned with what it needs to be concerned with.
Separation of Concerns
Lets start by identifying some of the concerns in your User class.
Inventory
Equipment
Quests
The above are the general resources that will be utilized by your user. Each of these also have things they are concerned with:
Inventory
Item
Equipment
Item
Quests
Quest
You can already see we have several separate parts of the user which require the same information.
Separating Logic From State
At this stage, we now need to separate some other concerns. Specifically, the business logic (what we want to do with our data) and the data access layer itself (the ORM/Models). Personally, I like to keep these things separate by using the Repository Pattern. Classes that work on models and are concerned with the overall logic and application process. I feel that models are a representation of state, and should only worry about fetching or persisting that state.
So I split these things out as such:
Models
User
Item
Quest
Repositories (dependencies)
UserRepository (User, Item, Inventory, Equipment, Quests)
InventoryRepository (Item)
EquipmentRepository (Item, Collection)
QuestRepository (Quest)
Code Examples
Now this gives me a clear definition of the setup and organization I want. But lets give some example code. This does not concern how the data is persisted (either manually, or via Eloquent relationships, etc).
<?php namespace App\Repositories;
use App\Models\Item;
use Illuminate\Support\Collection;
class Inventory {
protected $contents;
public function __construct(Item $item, Collection $contents)
{
$this->item = $item;
$this->contents = $contents;
}
public function add(Item $item)
{
$this->contents->push($item);
}
public function remove(Item $item)
{
$this->contents->forget($item->id);
}
public function contains(Item $item)
{
return $this->contents->has($item->id);
}
}
The InventoryRepository is only concerned with managing its collection of items. Adding them, removing them and checking if other items are there. To do this it depends on the Collection class and the Item model.
<?php namespace App\Repositories;
use App\Models\Item;
class Equipment {
protected $slots = [
'head' => null,
'body' => null,
'legs' => null,
'feet' => null,
'arms' => null,
];
public function __construct(Item $item)
{
$this->item = $item;
}
public function get($slot)
{
return $this->slots[$slot];
}
public function set($slot, Item $item)
{
$this->slots[$slot] = $item;
}
public function empty($slot)
{
$this->slots[$slot] = null;
}
public function hasEquipment($slot)
{
return !empty($this->get($slot));
}
public function isEquipped(Item $item)
{
if ($this->hasEquipment($item->slot))
{
return $this->get($item->slot)->id == $item->id;
}
}
}
Another class only concerned with the items currently equipped. Equipping, unequipping, etc.
Bringing It All Together
Once you've defined your separate pieces, you can then bring them all into your UserRepository class. By pulling them in as dependencies, the code contained within your UserRepository will be explicitly User management based, while accessing the loaded dependencies gives you all the functionality you require.
<?php App\Repositories;
use App\Models\User;
use App\Repositories\Inventory;
use App\Repositories\Equipment;
class User {
protected $user;
protected $quests;
protected $equipment;
protected $inventory;
public function __construct(
User $user,
Quests $quests,
Equipment $equipment,
Inventory $inventory
) {
$this->user = $user;
$this->quests = $quests;
$this->equipment = $equipment;
$this->inventory = $inventory;
}
public function equip(Item $item)
{
if ($this->inventory->contains($item))
{
$this->equipment->set($item->slot, $item);
}
}
public function unequip(Item $item)
{
if ($this->equipment->isEquipped($item))
{
$this->equipment->empty($item->slot);
}
}
}
This is again just a concept for organizing code. How you want to load and persist the data to the DB is up to you within this type of setup. This is also not the only way to organize the code. The takeaway here is how to break your code out into separate parts and concerns to better modularize and isolate functionality into easier to manage and digest bits.
I hope this was helpful, don't hesitate to ask any questions.
I think that your user has so many responsabilities. Take a look into SOLID principles. Start with Single Responsability Principle.
So take out from user inventory actions and put inventory responsabilities into Inventory service for example.
Yes I would abstract the business logic out to a service or repository layer.
Here is a good article:
https://bosnadev.com/2015/03/07/using-repository-pattern-in-laravel-5/
One of the issues of passing around model classes with attached functionality is the bloat that's inherent in a model class. Basically each model class carries around with it the weight of the entire database model, which is quite heavy. That's typical of an Active Record ORM implementation like Eloquent, as opposed to a Data Mapper style ORM like Doctrine. However I am guessing that having bitten the Laravel bullet you are more or less wedded to Eloquent.
One thing that I found, that loses the weight of the data model but keeps the OO style interface is to use Laravel's Fluent class. To aid in that I wrote a small extension here:
https://packagist.org/packages/delatbabel/fluents
Pull it in using:
composer require delatbabel/fluents

What is a strategy to ensure proper subclasses from a generalized search query?

Here's a generalized scenario. I have "Tasks" and I have "Task Events." I've created a database table for each. I've also created a model which handles fetching records from the database.
For "Task Events," I have a few types: Created, Accepted, Comment, Closed.
Currently, I do something simple like $task = new Task($task_id); to grab the task from the database, and $task_events = new Tasks_Events($task_id); which grabs the events for that task. Then, I've implemented Iterator so I can do foreach($task_events as $e) { ... } this is all working great.
However, I have found that I need some specialized handlers for a few of the event types. For example, I've created Tasks_Events_Comments which extends Tasks_Events, and does some extra processing for Comment event types. What I've realized now is that when I gather the collection of events, I really need them to be child types, so if a method is called on the event, the proper overrides from the child type are called.
Here's a quick example:
class Model {
public function __construct($search = null) {
// Hypothetical example, basically query the DB and populate data.
if (!is_null($search)) { $this->search($search); }
}
protected function onAfterUpdate() { }
}
class Tasks_Events extends Model {
protected function onAfterUpdate() { /* Task Event Specific */ }
}
class Tasks_Events_Comments extends Tasks_Events {
protected function onAfterUpdate() { /* Task Event Comment Specific */ }
}
Then, a hypothetical use case:
class Controller {
public function updateEvent($task_id, $event_id, $params) {
$task = new Tasks($task_id);
$task_event = new Tasks_Events($event_id);
// Some Analysis of Params
$task_event->status = $new_status;
$task_event->save();
}
}
So, HERE is the key. Doing it this way will call Tasks_Events onAfterUpdate()...
My question is, what is a model, paradigm, philosophy, approach that I can use so that when I have a collection of task events, and I action on one, even though I'm using a base class reference, I need to have the child classes functions called.
I really enjoy the simplicity of $e = new Tasks_Events(3); $e->status = 4; $e->save(); one solution I have which I don't like, is to do something like $e = Tasks_Events::Get($id); where Tasks_Events would query the database, determine the type, then do a "switch" and create the proper type to be returned.
Another reason I don't like that is because I've built up the model to do cool things like $tasks = new Tasks(array('user_id' => 5, 'status' => Tasks::STATUS_OPEN)); and it will build the proper db query, and populate with all of the tasks for user 5 that are open. Then I can do foreach($tasks as $t) { echo $t->subject; } etc. So, I'd love to be able to keep this sort of system.... but I'm not sure if I can if I want to take advantage of inheritance for sub-types.
I'm afraid I may need a Factory pattern, but I'm hoping I might just be missing something.
P.S. If you can think of a better title, feel free to change it.
Thanks #Sam Dufel, your comment made me think deeper and I realized a major flaw in my design.
You made a good suggestion of $task->getEvents(), but I forgot a crucial (flaw?) point in my question. This may also be the reason I've gotten into trouble...
Basically the way I implemented the Iterator, and getter/setters is probably the source of the problem. Since it iterates over an array of the raw records.
Then, let's say I'm at position 2 in the iterator. Calling $item->status, calls __get($name) which checks $this->records[$this->position][$name]!! So, as you can see, I painted myself into a corner. Even with a factory pattern, this wouldn't quite work because of the way I implemented the iterator inside of the Tasks_Events (well... the Model) argh.
Sorry to bother y'all. Thanks for the thoughts.
Update: What I realize I did was combined a "DAO" with a "Model" with a "Model Collection" in effect. I'm going to separate them. DAO->find() will return a Model Collection (which will be iterable), and DAO->findOne() which will return a Model. It was handy to have all three in one, but as my needs expanded, it was not very extensible.

Kohana 3 module structure question

everybody! I have a new question about Kohana 3, or rather about a module structure. I develop a small module called Textblock. It's about an ordinary page or a small insertion to the site layout (e.g. a greeting or a slogan, company name). It contains both controllers and models. Models inherit Sprig_MPTT. And one feature I'd like to implement is one could be able to call this module like this:
$textblock = Textblock::get_single(1); //by id
$children = Textblock::get_children_of(4); //id of parent
and not
$textblock = Sprig::factory('Textblock')->get_single(1);
$children = Sprig::factory('Textblock')->get_children_of(4);
Those methods are defined in Model_Textblock class as static.
So, I made a wrapper class Textblock, that inherits Model_Textblock. What if I suddenly want change Sprig to Jelly, for example? Foreground won't change at all. Another advantage, imho, is more clarity for anyone, who wants to use this module (e.g. it could be another programmer in the team).
But there's a doubt if I'm on a wrong way... So, the question itself: is the suggested a right way to organize my module? Or it's preferable to keep ordinary Sprig::factory('Textblock') where Textblock's functionality is needed, remove additional wrapper class and remove static?
There is no need to extend Model_Textblock. You can create a model instance and call its method:
class Textblock {
public static function get_single($id)
{
return Sprig::factory('textblock')->get_single($id);
}
// etc
}
But this way you should copy model methods in your static class (not DRY). Also, what if you have more than one model? All you want (as I understand) is to easily change AR driver. So I'd preffer this kind of class:
class Textblock {
// saved objects, dont create on model twice
protected static $_instances = array();
public static function model($name)
{
if (! isset(self::$_instances[$name]))
{
$model = Sprig_MPTT::factory($name);
// you can add try..catch to prevent exceptions
// or add another checks
self::$_instances[$name] = $model;
}
return clone self::$_instances[$name];
}
}
and use it like Textblock::model('textblock')->get_single($id).

How to design Models the correct way: Object-oriented or "Package"-oriented?

I know that in OOP you want every object (from a class) to be a "thing", eg. user, validator etc.
I know the basics about MVC, how they different parts interact with each other.
However, i wonder if the models in MVC should be designed according to the traditional OOP design, that is to say, should every model be a database/table/row (solution 2)?
Or is the intention more like to collect methods that are affecting the same table or a bunch of related tables (solution 1).
example for an Address book module in CodeIgniter, where i want be able to "CRUD" a Contact and add/remove it to/from a CRUD-able Contact Group.
Models solution 1: bunching all related methods together (not real object, rather a "package")
class Contacts extends Model {
function create_contact() {)
function read_contact() {}
function update_contact() {}
function delete_contact() {}
function add_contact_to_group() {}
function delete_contact_from_group() {}
function create_group() {}
function read_group() {}
function update_group() {}
function delete_group() {}
}
Models solution 2: the OOP way (one class per file)
class Contact extends Model {
private $name = '';
private $id = '';
function create_contact() {)
function read_contact() {}
function update_contact() {}
function delete_contact() {}
}
class ContactGroup extends Model {
private $name = '';
private $id = '';
function add_contact_to_group() {}
function delete_contact_from_group() {}
function create_group() {}
function read_group() {}
function update_group() {}
function delete_group() {}
}
i dont know how to think when i want to create the models. and the above examples are my real tasks for creating an Address book. Should i just bunch all functions together in one class. then the class contains different logic (contact and group), so it can not hold properties that are specific for either one of them.
the solution 2 works according to the OOP. but i dont know why i should make such a dividing. what would the benefits be to have a Contact object for example. Its surely not a User object, so why should a Contact "live" with its own state (properties and methods). Cause i tend to think like this: If something needs a state, then i create a OOP class so that the methods could affect the state or other things based on the state.
so should models be "stateful" too? if they require no state, why should i create it according to the OOP pattern. then i could just bunch it all together like the "package" solution.
you experienced guys with OOP/MVC, please shed a light on how one should think here in this very concrete task (and in general when creating a model)
EDIT: come to think about Controllers in MVC. they are created according to the "package" solution. It makes me wonder...
should every model be a
database/table/row (solution 2)?
No. Don't tie the definition of a model to its method of persistence. Although for simple applications you might extend a model from a database row object, you should keep them at least mentally separated.
Models are simply representations of entities in your domain, so by necessity they have state. Where you talk about a Contact model, you are really talking about a mapper or gateway, i.e. the object retrieving your model from the data store. It's unfortunate that so many ad hoc implementations of Active Record have muddied the waters on this.
Mappers can be implemented as a collection of static functions or as an object - however, the collection is less flexible if you want to extend or alter the behaviour for any reason (such as mocking for unit testing).
The model itself should simply be a collection of data, either stored as public properties or preferably with appropriate setters and getters (please don't just define a get/set function pair for every variable or you might as well just leave them public), along with other methods that operate on the data. It should have no concept of, or dependency on, the data store. It is the responsibility of the mapper to instantiate and initialize the model through its interface. Doing this will afford flexibility in how you can create and save your models. You can do it from the database, an XML file, in-code, from a serialized stream sent in over the network, whatever floats your boat really, all by substituting a different mapper, and the model remains completely unaware.
I don't know if there's a best way, but i'll share the way i do it...
I have a table gateway e.g. ContactTableGateway that contains all the sql for dealing with contacts. I like all the sql being in one place.
class ContactTableGateway extends Model {
function saveContact( Contact $contact )
function getContact ( $contact_id )
function createContact ( Contact $contact )
}
Then i have a contact class that basically just has getters and setters ( or public properties ). Objects of this class are used as arguments for the table gateway to save/create
class Contact extends Model {
function getName()
function getAddress()
function getEmail()
....
}
Heres a simplified example
if ( isset( $_POST ) ) {
// some validation here
$contact = new Contact;
$contact->name = $_POST['name'];
$contact->email = $_POST['email']
$contactTableGateway = new ContactTableGateway;
if ( $contactTableGateway->createContact( $contact ) ) {
echo "YAY";
}
}
I think your Solution #2 is superior as it's more molecular/modular, therefore, more understandable, flexible and extensible (in the OOP domain). It's also more resource friendly as it could allow you to only have to load the Contact class when no contact group functionality is required and vice-versa. That is the benefit of division.
If models need no state, that does not mean OOP/MVC does not apply. Table models may have no state in one's design but that is why we have static methods/members, i.e., Contact::read($id).

Zend Framework: Using Models and Views, best practices [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I'm relatively new to Object Oriented Programming. I pretty much understand the concepts, but practically speaking, I am having a really hard time finding information about how to best use Models in my Zend Framework applications.
Specifically, I have a Model (that doesn't extend anything) that doesn't use a Database Table. It uses getters and setters to access its protected members. I find myself struggling with how to best display this model in the view. I don't want logic in my view templates, but I find myself in the following situation:
In my controller:
$object = new Object();
$object->setName('Foo Bar');
$this->view->object = $object;
In my view template:
<h2><?= $this->object->getName() ?></h2>
I don't really like calling functions in my view templates but I don't know a better way to do this. I don't want my Model's members to be public, but I basically want to achieve the same results:
<h2><?= $this->object->name ?></h2>
I don't want my controller to do all the work of having to know everything about the model:
$object = new Object();
$object->setName('Foo Bar');
$this->view->object = $object;
$this->view->object->name = $object->getName();
What is the best practice of using models in the Zend Framework? Can anyone recommend any tutorial that would help me understand this Model/View dilemma in Zend Framework?
One possibility is to use the magic __set and __get methods in PHP. I use them like so within my abstract Model class:
abstract class Model_Abstract
{
protected $_data;
// Private Data Members assigned to protected $_data
public function __construct($data = null)
{
// Makes it so that I can pass in an associative array as well as
// an StdObject.
if(!is_object($data)) {
$data = (object) $data;
}
$this->_data = $data;
}
public function __get($key)
{
if (method_exists($this, '_get' . ucfirst($key))) {
$method = '_get' . ucfirst($key);
return $this->$method();
}
else {
return $this->_data->$key;
}
}
public function __set($key, $val)
{
if ( method_exists( $this, '_set' . ucfirst($key) ) ) {
$method = '_set' . ucfirst($key);
return $this->$method($val);
}
else {
$this->_data->$key = $val;
return $this->_data->$key;
}
}
}
class Model_User extends Model_Abstract
{
//Example overriding method for the property firstName in the $_data collection.
protected function _getFirstName()
{
// Do some special processing and then output the first name.
}
}
This makes it so that you can specify getters and setters for properties as necessary but makes it so that you don't have to define boilerplate functions for every property, just the ones where you want to do some sort of processing on it before returning the value. For example I use the functionality in a number of places to change ISO compliant dates (as stored in MySQL) into a more compact and readable format for users.
As far as what to place in your controller, I would recommend looking at this post for some specific feedback on what handling to place within your controller.
Some feel that they would rather have a helper that automatically loads models into the view and skirts the controller altogether. Personally I would say that within the context of Zend Framework and PHP it makes plenty of sense to pass models into the view from the controller because the state of the models in the view frequently depends on what came from the request (which should definitely be handled in the controller).
Update: As per criticisms in the comments, one thing that I would point out is that your database access layer and domain (or model) layer are really two different things, though with the Active Record they are blended together. I asked this question a while back and received some useful feedback on this matter. Whatever you decide to do with the model, you'll want to provide a consistent API for all domain objects regardless of where the data for the model comes from.
I suppose that one benefit offered by Saem's answer is that it offers the ability to directly map properties / function return values from one or more domain objects to the view object. Theoretically the usage within the view then looks like this:
// Mapped from Model_User::_data->last_name and Model_User::_data->first_name
$this->name
If only other developers are going to be working with the templates, I would recommend just passing in the models. Here is a link to a Jeff Atwood post on MVC Understanding Model-View-Controller
This isn't particularly geared towards zend framework, but the problem is rather general, in my mind.
It seems you're on the right path, instead of hard wiring the model to the view, inside the controller. You'd rather have that abstract, especially important if you're mapping a tonne of models, or mapping the same model over and over again.
Something simple would be to write a bunch of mapping functions, which would be fine if all you were avoiding is mapping the same thing over and over.
If you wanted a more general solution, that also addressed avoid writing that boiler plate code, and keeping things more DRY, I suggest creating a mapper class.
You could create a ViewModelMapper, which would take a model, or a few models and map them to the view.
class ViewModelMapper
{
public function __construct($view)
{
//set the properties
}
public function addModel($model, $overrideViewProperty = null)
{
//add the model to the list of models to map, use the view's property
// name to figure out what to map it to? Allow for an override just in case.
}
public function getMappedView()
{
//take the view, map all the models
}
}
You could then instance this on your controller, and setup the mappings, so the controller controls the mapping still, but all the boiler plate and coding logic is centralized, for all controller maps, except for the rare exceptions.
For a good read on model architecture, read this post. It doesn't specifically talk about the view, but it's definitely worth reading.
I ended up adding a getViewClass() function to my models. The controller calls this function to get the protected variables it wouldn't otherwise have access to, and the view doesn't have to worry about calling any getters.
//controller
$object = new Object();
$object->setName('Foo Bar');
$this->view->object = $object->getViewClass();
//view template
<h2><?= $this->object->name ?></h2>
I don't know if there is a better way to get the job done in the Zend Framework, but this is one solution.

Categories