Welcome Guest, Not a member yet? Register   Sign In
[Deprecated] DMZ 1.6.2 (DataMapper OverZealous Edition)

[eluser]OverZealous[/eluser]
@someoneinomaha
Save yourself the trouble, check out Deep Relationships

[eluser]Oblique[/eluser]
@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:

Code:
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!
            }
        }
    }
...

Code:
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

[eluser]The Hamburgler[/eluser]
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:
Code:
... 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???

[eluser]PoetaWD[/eluser]
Just found the answer... thanks

[eluser]OverZealous[/eluser]
@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().

[eluser]The Hamburgler[/eluser]
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.

[eluser]OverZealous[/eluser]
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.

[eluser]beemr[/eluser]
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:
Code:
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.)

[eluser]OverZealous[/eluser]
@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.

[eluser]beemr[/eluser]
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:

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]);
                        }




Theme © iAndrew 2016 - Forum software by © MyBB