CodeIgniter Forums
DataMapper 1.6.0 - Printable Version

+- CodeIgniter Forums (https://forum.codeigniter.com)
+-- Forum: Archived Discussions (https://forum.codeigniter.com/forumdisplay.php?fid=20)
+--- Forum: Archived Libraries & Helpers (https://forum.codeigniter.com/forumdisplay.php?fid=22)
+--- Thread: DataMapper 1.6.0 (/showthread.php?tid=11358)



DataMapper 1.6.0 - El Forum - 04-16-2009

[eluser]naren_nag[/eluser]
I am facing a very very strange issue -- and this has just cropped up.

When I do a get_by_id and pass any id, the object always returns the same record.

Eg.

$id = 18;
$work->get_by_id($id);
echo $work->id;

the output is ALWAYS 16. No matter what I set $id as. I'm checking the value of $id just before I do the get, and I've tried where->get as well. Same issue.

Does anybody have any clue! HELP!


DataMapper 1.6.0 - El Forum - 04-16-2009

[eluser]OverZealous[/eluser]
Try turning on CodeIgniter's profiling, which should show you what queries are being run. At least you can try to see if the correct ID is getting to the query or not.

DataMapper does not have any known problems with get_by_id, so the bug might be either with custom code on your end, or your database. Also, make sure you aren't accidentally overwriting any reserved names.


DataMapper 1.6.0 - El Forum - 04-16-2009

[eluser]naren_nag[/eluser]
Thanks Phil, am checking the reserved names things immediately and will then go down the profiling route.


DataMapper 1.6.0 - El Forum - 04-16-2009

[eluser]bEz[/eluser]
Well, Phil... the bad seems to come with the good, at least for now...

[quote author="OverZealous.com" date="1239854546"]
There's nothing "wrong" with saving to the id's directly, I guess I should have made that clear. It can even save a lot of time on the DB, if you trust the users.
However, there's no validation being done on that id, so someone could send the server an invalid id, and really break your application, possibly even getting access to someone else's data. I always recommend writing code as if every user was trying to break the server.
[/quote]

I do trust the users because:
1) They are managed by a user authorization script.
2) The available Zone IDs are provided by a dropdown.
3) However, I do and will maintain the notion that "every user is trying to break the server"


[quote author="OverZealous.com" date="1239854546"]
In other words, I would look up the related object by id, and then save that object using the normal $object->save($related). Of course, if you decide to do this, you'll have to enable NULL values for the related columns, because DM doesn't save relationships until after saving $object.

As for needing the rule on both, it probably isn't necessary. The rule runs either way, and checking both just doubles the queries. The only drawback to running on just one is that you won't get an error message on the other field.
[/quote]
I updated the object_id for Zone and Season tables to allow NULLS
I modified the create method of the season model by:
A) instantiating a new zone object
B) getting data via get_by_id(zone_id) passed in from form dropdown.
C) checking if the zone->exists()

The problem is that if I try and save that object using the normal $object->save($related)
Code:
$s->save($z)
I can no longer use unique_pair validation on zone_id, because I would no longer be "DIRECTLY" saving the zone_id.
I had to remove the Validation portion for zone_id and the seq because without it being "directly set" it would fail to save.

Unfortunately, with it removed, if there was an attempt to duplicate a combination of the zone_id and the seq, it would save the season with a NULL zone_id. Also, I could not return any error strings when the save failed due to duplicate entry.

So basically, I did a mix of checking for zone existence, and if so, "directly saving" as before, as well as taking advantage of the unique_pair validation rule.

The problem I fair is that as I continue to develop, this will be a thorn in my side if your suggestions are possible and I did not resolved this.
For my scenario as it stands, i'm wondering if the functionality just isn't coded into DMZ, or is somehow a bug.

Provided the current "working" model file. Hope you can assist with further troubleshooting.
Code:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Season extends DataMapper {
  
   var $table = 'seasons';
   var $has_many = array('commissioner', 'registration', 'conference');
   var $has_one = array('zone');
   var $validation = array(
          array(
            'field' => 'zone_id',
            'label' => 'Zone',
            'rules' => array('required', 'trim', 'unique_pair' => 'seq')
          ),
          array(
            'field' => 'seq',
            'label' => 'Season #',
            'rules' => array('required', 'trim', 'unique_pair' => 'zone_id')
          ),
        );

    function Season()
    {
        parent::DataMapper();
    }

    function create($data=NULL)
    {
    $zone_id = $data['zone_id'];
    $seq = $data['seq'];

    $z = new Zone();
    $z->get_by_id($zone_id);

    if ( $z->exists() )
    {
      $s = new Season();
      $s->zone_id = $zone_id;
      $s->seq = $seq;
      $s->gametitle_id = $data['gametitle_id'];

      if ( $s->save() )
        return array('success' => TRUE, 'message' => "Record successfully created.");
      else
      {
        $error_msg = $s->error->seq . 'Zone: ' . $zone_id . br() . ' Season: ' . $seq;
        return array('success' => FALSE, 'message' => $error_msg);
      }
    } else
    {
      $error_msg = 'Cannot Save Record, Zone no longer exist!';
      return array('success' => FALSE, 'message' => $error_msg);
    }
  }
}
/* End of file season.php */



DataMapper 1.6.0 - El Forum - 04-16-2009

[eluser]OverZealous[/eluser]
You have two options. Either continue with what you had been doing (and that's fine, and it's the fastest solution), or write a custom _related rule. There's a section on that in the docs. I'm not sure you would be able to get that to work, though, because both fields wouldn't be set at the same time.

So, I guess I would recommend using the previous method and sticking with the unique_pair.

I wonder if it would be worth adding "custom_field_validation" and "custom_related_validation" methods to DMZ that runs after all of the other rules are run, for complicated validation that needs to happen after everything else has been checked, but before saving or committing a transaction.


DataMapper 1.6.0 - El Forum - 04-16-2009

[eluser]naren_nag[/eluser]
Okay! It was a problem with the reserved names. I've implemented a networked tree and I'm keeping track of parents by calling the field parent. Name changed, problem solved. Thanks a lot.


DataMapper 1.6.0 - El Forum - 04-17-2009

[eluser]bEz[/eluser]
@Phil
[quote author="OverZealous.com" date="1239947241"]You have two options. Either continue with what you had been doing (and that's fine, and it's the fastest solution), or write a custom _related rule. There's a section on that in the docs. I'm not sure you would be able to get that to work, though, because both fields wouldn't be set at the same time.

So, I guess I would recommend using the previous method and sticking with the unique_pair.

I wonder if it would be worth adding "custom_field_validation" and "custom_related_validation" methods to DMZ that runs after all of the other rules are run, for complicated validation that needs to happen after everything else has been checked, but before saving or committing a transaction.[/quote]

Thanks for the guideance so far. I am comfortable with what I've done so far, but I in way I don't want to lose sight of what DMZ/DataMapper functionality may be able to improve on.

Well, you mentioned a possible keyword "TRANSACTION."
Since I use the InnoDB engine, I will try and utilize that approach of Datamapper (CodeIgniter)

Basically, it should save having to attempt a custom validation rule, especially since the validation would be based on the INDEX and not the columns.
I wouldn't pull any hairs on modifying DMZ just yet though, this functionality may have a solution as it stands.

Thanks again Phil...
-bEz


p.s. - FOREIGN KEYS, can you provide a brief summary why FOREIGN KEYS are not used (supported, required, etc.) with DataMapper/DMZ?


DataMapper 1.6.0 - El Forum - 04-17-2009

[eluser]Burgestrand[/eluser]
Been pulling my hair a while, pondering why I could log in without supplying proper credentials, even following the user guide example.

Line 451 <datamapper.php>, “$data = $this->_to_array(TRUE);”, why is this flag set to TRUE? Consider the following code:
Code:
$user = new User();
$user->username = $this->input->post('username');
$user->password = $this->input->post('password');
$user->validate()->get();
if ( ! empty($user->username)) /* authenticated stuff */

With flag set to TRUE the post-validation fetching becomes:
Code:
$user->where('username', $this->username)->get()
(effectively logging the visitor in without needing a password)
With flag set to FALSE:
Code:
$user->where('username', $this->username)->where('password', $this->password)->get()

… or have I missed something obvious in my 5 AM coding spree?


DataMapper 1.6.0 - El Forum - 04-17-2009

[eluser]OverZealous[/eluser]
@bEz
I'm not the original author, but the basic reason foreign keys are not used is that they provide no benefit. There's no way to get feedback about foreign keys from the database in a consistent way. The server still has to check on those restrictions by hand.

If you want to use foreign keys, you can, but I have a feeling that they might cause errors. That being said, some databases use foreign keys to speed up queries, so just adding in the reference (without any other restrictions) might work.

@Burgestrand
That call is important, otherwise the query would include every empty or null field on the table in the query, and probably never return a result. If you look at _to_array(), it's easy to see what that flag means.

You are actually doing it wrong, if the copied code is correct. Look at the example again. Notice that the user is looked up by email first, then the email and salt is copied over to a new account. That account has the password validated, and then the validate/get is run.

Also, I think you might not have required on your password field, which is why the validation routine succeeds on an empty password. If someone is able to log in with an empty password, that failure is most likely at the validation(), not the get().


DataMapper 1.6.0 - El Forum - 04-17-2009

[eluser]Burgestrand[/eluser]
The login method actually looks like this:
Code:
$user = new User();
$user->where('username', $this->username)->get();
$this->salt = $user->salt;
$this->validate();
var_dump($this->password, $this->error->string);
$this->get();
return ! empty($this->username);
I'm dumping the data to find wherever my error is located, with the following result:
Quote:bool(false) string(392) "
The Username field is required.
The Username field must be at least 1 characters in length.
The Password field is required.
The Password field must be at least 6 characters in length.
The E-Mail field is required.
The E-Mail field must be at least 5 characters in length.
"

I believe the problem is in the validation condition checking. Line 444(still datamapper.php), “if ($this->validated)” — sure, it has been validated but it was found not valid, and I can't find any check to make sure it has been before fetching the new data.

I'll go to sleep and look at this in the morning, I think it's needed. ¬¬