@someoneinomaha
Save yourself the trouble, check out Deep Relationships
This is an archived forum and the content is probably no longer relevant, but is provided here for posterity.
The active forums are here.
November 23, 2009 11:54pm
Subscribe [46]#271 / Feb 15, 2010 11:40pm
@someoneinomaha
Save yourself the trouble, check out Deep Relationships
#272 / Feb 16, 2010 12:26am
@NachoF, i don’t like per-method authorization too. That’s why i use AOP-like feature (make some coffee, so you don’t accidently fall asleep while reading this):
1) we implement our own “template” controller in libraries folder, “MY_Controller”, from which our other controllers descend.
2) in MY_Controller’s constructor we define $this->current_user (i use tank_auth, but don’t like it much, though it’s not bad) and analyse uri - basing on what segment(1) is set to, we decide, if this section is accessible by current_user or not.
3) After it, if you have to restrict users from some particular methods, access to which depends on user’s behaviour, you could do this in same MY_Controller’s contructor.
My implementation of this approach looks like this:
MY_Controller.php
...
public function __construct()
{
parent::__construct();
// Defining which controller and method are requested:
$this->controller_name = $this->uri->rsegment(1);
$this->current_action = $this->uri->rsegment(2);
// Loading configs and langs if necessary, etc.
...
// Defining dmz-model User. Can be used in descendant controllers for user-depending things
$this->current_user = new User($this->tank_auth->get_user_id());
// If user requested not-restricted controller…
if ( ! (User::is_restriced($this->controller_name)))
return;
// if he's not logged in, or if his role doesn't allowed here, he's kicked out
if ( ! ($this->current_user->exists() AND $this->current_user->authorize($this->controller_name)))
{
redirect('/auth/login/');
}
// if he requested method, he doesn't have permissions for,
// he's either kicked out or recieves some message
elseif ( ! $this->current_user->has_access_to($this->current_action))
{
// naa-na-na-na
// na-na
// na-na
// can't touch this!
}
}
}
...user.php
...
public static $restrictions = array
(
'admin' => array(),
'carrier' => array
(
'freightages' => 1,
'freightage_take' => 2,
'freightage_lock' => 4
),
'shipper' => array
(
'freightage_new' => 1,
'shippers_view' => 2
)
);
public static function is_restriced($controller)
{
return array_key_exists($controller, self::$restrictions);
}
function authorize($controller)
{
return $this->role == $controller;
}
function has_access_to($action)
{
// This also could be done with the use of SET sql data type, but since dmz
// doesn't have means to easily do that (not meant as a reproach),
// it's easier to make it yourself
// If this action is restrictable
if (array_key_exists($action, self::$restrictions[$this->role]))
{
// If permissions property of user has parmission flag of this action set to 1
return (self::$restrictions[$this->role][$action] & (int)$this->permissions) !== 0;
}
return TRUE;
}
...If you have nested directories of controllers, this would look a bit more complicated around that line where current controller and method is defined
#273 / Feb 16, 2010 8:16am
Quick question.
- Need to display a table of filtered dm records
- There are +1000 records in the db so the table needs to be paged.
- The table is dynamically filtered by post/session data
So far my code looks like this:
... Controller
// load dm model
$this->load->model('contact');
// method adds relevant dm 'where' clauses to object
$this->filter();
// get count of filtered records
$count = $this->contact->count();
// get filtered records
$this->contact->get(20, $offset);This code will not work because after count() is called the sql clauses set by filter() will be lost.
If I comment out $this->contact->count(); and use count($this->contact->all) instead the maximum count possible will be 20.
I’m looking for a elegant way to retrieve both a full count of filtered records and a paged subset of filtered records without having to call filter twice.
Any ideas???
#274 / Feb 16, 2010 10:23am
Just found the answer… thanks
#275 / Feb 16, 2010 12:49pm
@The Hamburgler
Look back about 2 pages. This was just discussed in the last week, and I provided a couple of solutions.
Why wouldn’t you call filter() twice? The call to filter is probably a several order-of-magnitudes faster than the actual queries.
Also, Don’t manually load models! DM automatically handles loading all of the models, so you should never, ever make a call to $this->load->model().
#276 / Feb 16, 2010 1:19pm
Oops, now I feel bad. Thanks a lot.
At the moment filter() is also doing some work prepping data for the filter view. Calling it twice would be a waste.
There’s an argument for splitting these two behaviours into different methods, which I may do eventually.
I’m using global instances of datamapper models in my controller most of the time, so calling $this->load->model(‘contact’) instantiates $this->contact automatically. I guess i’ll just do $this->contact = new Contact(); instead from now on.
#277 / Feb 16, 2010 1:24pm
The Hamburgler
The latter would be more efficient (new Contact()), simply because you are otherwise re-loading the PHP file each time. It’s probably almost insignificant in the overall speed.
#278 / Feb 16, 2010 6:15pm
First off, great library. I used to use Active_Record_Mod but I am loving the thought that you’ve put behind this.
So now to my problem. I have a custom validation on an unrequired field so it is set to “always_validate”. Since the field isn’t required, it’s initial value in the database is NULL. Now, even if the field is left empty, it will overwrite the NULL to ‘’ upon calling save(). All subsequent attempts to run the custom validation will fail since datamapper will unset unchanged values (as it should).
To solve for this, I added a check against NULL stored values when the submitted value is empty.
Added at line 1002 of datamapper.php:
if ($this->{$field} === $this->stored->{$field} ||
(NULL === $this->stored->{$field} && empty($this->{$field})))This way I can freely update the whole model without breaking my custom validation rule. What do you think?
(For what it’s worth, the custom rule created a requirement dependency based on the value of another field.)
#279 / Feb 16, 2010 6:34pm
@beemr
I cannot find that line, since the upcoming version of DMZ I’m working on has a lot of changes. Which method was that in?
(Also, you could just manually set the value of the field to NULL in your custom field if you want it NULL.)
Update Oops, I accidentally my verb.
#280 / Feb 16, 2010 7:12pm
The field in question is a textarea, so NULL is not available as a preset value.
I added the NULL check in the function: function save($object = ‘’, $related_field = ‘’)
Here’s some of the context code:
// Convert this object to array
$data = $this->_to_array();
if ( ! empty($data))
{
if ( ! $this->_force_save_as_new && ! empty($data['id']))
{
// Prepare data to send only changed fields
foreach ($data as $field => $value)
{
// Unset field from data if it hasn't been changed
if ($this->{$field} === $this->stored->{$field} ||
(NULL === $this->stored->{$field} && empty($this->{$field})))
{
unset($data[$field]);
}#281 / Feb 16, 2010 7:16pm
I see what you have done, but that makes it impossible to set an empty string field in the database, and could also throw an error for NOT NULL columns where empty fields are allowed. All stored fields start out as NULLs, so this could be an issue.
Basically, NULL != ‘’.
What I meant earlier was set the field in your custom validation rule (not field). That’s the appropriate place to make the change:
_my_custom_rule($field, $params) {
if( /* check for null */) {
$this->{$field} = NULL;
} else {
// whatever else
}
}#282 / Feb 16, 2010 7:29pm
It’s just the reverse, actually. An empty textarea always posts a value of ‘’, whether it is required or not. That means that the initial NULL is always overwritten with ‘’. If custom validation decides that the textarea should be required later on, there will be no chance to cause a validation because the save() function unsets any values that are the same as the stored value.
I.E. Upon setting a task as “Completed”, I want to require a “sunset review” comment. Unfortunately, when the task was originally set to “Assigned”, it replaced NULL in the db with a ‘’. Now, when I want the task set to “Completed”, the textarea submits a ‘’ which matches the stored value and unsets itself upon save.
#283 / Feb 16, 2010 7:32pm
I can see what you mean, though. If an empty string and a NULL are both valid values for a db field, my modification would be a problem. Hmmm.
#284 / Feb 16, 2010 7:35pm
I think the issue you are having is that you are setting a value to be the same as it is.
If you need to force a change, why not do it in the controller? Also, you can override save() in your model, which gives you a chance to perform one-off things like this.
class MyModel extends DataMapperExt {
...
save($object = '', $related_field = '') {
// handle the special field here
$parent::save($object, $related_field);
}
...
}#285 / Feb 16, 2010 7:56pm
I want the textarea to be available even when it is not required, but the consequence of that is that the textarea will always post an empty string to the controller. I like having the validation rules in the model, but I suppose I can set the rules in the controller this time. Less elegant, though 😊
Essentially, I don’t want an empty string to be allowed to replace a NULL. I understand if that is too onerous a schema to impose. Thanks for the tips, though.