Welcome Guest, Not a member yet? Register   Sign In
DataMapper 1.6.0
#31

[eluser]GregX999[/eluser]
In reply to the chicken dish and Joe's Diner examples...

That's perfect, the ability to chain models is very handy! That would make life much easier.

(ie: foreach($restaurant->menu->menu_item as $mi)Smile

It'd be sweet if you could do something like this:

$menuitem = new MenuItem();
$menuitem->where('dish', 'chicken')->where('menu->restaurant', "Joe's Diner"->get();

instead of having to manually do a foreach loop.



Can use "assign" relations before issuing a save call?
Like this:

$restaurant->menu->menu_item = 'Chicken'; (or $restaurant->menu->menu_item->add('Chicken');
$restaurant->save();

Otherwise you'd have to do it like this right?
$restaurant->menu->menu_item->save($new_item); (having already created "$new_item" as a menu_item object



Also, can you delete like this?
$c->where('name', 'Australia')->get()->delete();



As far as requiring join tables for one-one and one-many relationships... I don't think it's valid to say "it was easier to program that way", becuase now it's more work for someone using the library to create more tables. As for not wanting tables to know about each other (and therefore not having foreign keys), it's an interesting way of looking at things. Are there any reasons you can see that would make that a desirable thing? I can't really think of any major pros/cons either way off the top of my head. It's something I certainly could get used to if I started using it.

One thing that could make life easier as far as managing lots of join tables is if you could manually set a join table name "prefix" (in database.php config file for example) so all join tables would appear together in an alphabetical list of table names (using "join_" or "_" for example).


Thanks,
Greg
#32

[eluser]GregX999[/eluser]
It would also be nice to have a "dump" function (for debugging, logging, etc.) that would output all the fields and their values for a given object. (But only database fields, not other class variables.)

Like this:

$u = new User();
$u->where('id', 1)->get();
$u->dump();

would return:
array(id=>1, name=>'Greg', username=>'gregx999', password => '********')

('password' would be a "special" protected field that could be flagged that way in the model... thus outputting '*' characters.)

Does DataMapper know all the fields in a table? Or would they have to be declared them in the model (which would make this feature not as usable)?

Greg
#33

[eluser]GregX999[/eluser]
I'm trying the following and am getting an error:

In the User model:

Code:
function signin($email, $password)
{
    $this->email = $email;
    $this->password = $password;
    $this->validate()->get();
    ...
}

I call validate so the "encrypt" method is called on password. This is very similar to one of your examples. (My encrypt method doesn't use a salt.)

But I get the error:

Message: Invalid argument supplied for foreach()
Filename: models/datamapper.php
Line Number: 505

Greg
#34

[eluser]stensi[/eluser]
Wow, lots of questions there! Thanks for your testing Greg. You've pointed out a bug to me I hadn't noticed.

The get() method has an "if ($this->valid)" check where it shouldn't. I meant to only include that in the the save() method. The fix is in version 1.2.1 which I've released. Using that version will see your $this->validate()->get(); call work correctly.

There's several ways you can do a "signin" method for a user. You don't have to pass the email and password as you have, since you can assign the values directly to the user object before calling signin(), but there's nothing wrong with doing it your way. You could even set it up to allow doing both ways (this example is without a database stored salt, so I'd assume we'd have an _encrypt method that uses the salt setup in the CodeIgniter config file):

Controller
Code:
// Directly assigning values before calling signin()
$u = new User();

$u->email = $this->input->post('email');
$u->password = $this->input->post('password');

if ($u->signin())
{
    // Signed in
}

// or

// Supplying values to signin()
$u = new User();

if ($u->signin($this->input->post('email'), $this->input->post('password')))
{
    // Signed in
}

Model
Code:
function signin($email = '', $password = '')
{
    if (!empty($email))
    {
        $this->email = $email;
    }

    if (!empty($password))
    {
        $this->password = $password;
    }

    // Cause validation rules to run (such as encrypt) and then try to get a matching record from the database
    $this->validate()->get();

    // If we have an ID, this user object is valid and fully populated (else its emptied)
    if (!empty($this->id))
    {
        // Create logged in session
        $this->session->set_userdata(array('id' => $this->id));

        return TRUE;
    }
    else
    {
        $this->error_message('signin', 'Email or password invalid');

        return FALSE;
    }
}

Yep, DataMapper knows all the fields in a table so you don't need to declare them in your models.

DataMapper currently has a private method that converts the objects field properties into an array (for internal use), but you can call it this way if you're needing a dump like method:

Code:
// Create your object and populate with all records
$o = new Object();
$o->get();

// Convert first record into an array
$array = $o->_to_array();

Note that the resulting array doesn't include any field properties with an empty value.

I'll have a look into having an optional db_prefix for join tables.


Other things in the works

zeratool has request I add in Database Transactions so that will be in the next version. You can set a bool to turn on automatic transactions or you can leave that off and manually call the transaction methods yourself.

I'm working on improving how you use and setup validation for the fields (as well as fields that don't exist in the database, only on the front-end, such as "password confirmation").

I'm also looking at setting up the ability to allow DataMapper to automatically create your Database Tables (both normal and joining table) if they don't already exist. If you want to use this feature, it would require you to define your normal tables within each of your models. I'll be using DBForge for this.
#35

[eluser]hugslife[/eluser]
Hi, thanks for this. It's really cool, and while I think I have a grasp using it for queries, I'm afraid I have to ask an ignorant question: What is the best way to pass results from the controller to the view?
Or is the following meant to be called from the view?
Code:
$u = new User;
$u->get();
#36

[eluser]GregX999[/eluser]
[quote author="stensi" date="1222143778"]I'm working on improving how you use and setup validation for the fields (as well as fields that don't exist in the database, only on the front-end, such as "password confirmation").[/quote]

Yes, please hurry up with this one!! Smile I'm trying to do a password confirmation right now and am running into some difficulties.

Greg
#37

[eluser]stensi[/eluser]
@hugslife: No problem. The usual way to pass data from the Controller to the View is like so:

Code:
<?php
class Blog extends Controller {

    function index()
    {
        $data['title'] = "My Title";
        $data['heading'] = "My Heading";
        $data['message'] = "My Message";
        
        $this->load->view('blogview', $data);

        // or you could build your "data" array like this:

        $data = array(
            'title' => 'My Title',
            'heading' => 'My Heading',
            'message' => 'My Message'
        );

        $this->load->view('blogview', $data);
    }
}
?>

For DataMapper objects, you can do it depending on your personal preference. That is, you could give the View only the data you want from your DataMapper objects:

Code:
// In Controller
$u = new User();
$u->get();

$data['username'] = $u->username;
$data['email'] = $u->email;

$this->load->view('myview', $data);

// In View
echo $username;
echo $email;

Or put the objects in the array you send the view:

Code:
// In Controller
$u = new User();
$u->get();

$data['u'] = $u;

$this->load->view('myview', $data);

// In View
echo $u->username;
echo $u->email;
#38

[eluser]hugslife[/eluser]
awesome stensi, that did it! i appreciate your help :-)
#39

[eluser]gusa[/eluser]
great job, stensi!!! ;-)
i downloaded datamapper yesterday and it's perfectly working under MSSQL Server.

however, a single restriction prevents me from starting a new project with this release: the "chicken issue". suppose my system handles 100.000 restaurants and each restaurant has 10.000 menu items (that's unrealistic, but it ilustrates my problem). both approaches that you suggested are too much memory consuming.

[quote author="stensi" date="1222080291"]
2:
Ok, so the Restaurant has a One to One relationship with Menu, and Menu has a One to Many relationship with MenuItem.
[/quote]

to simplify the problem, let's assume that we have restaurants and items. so, Restaurant has a One to Many relationship with Items. if i want to list all the restaurants that serves chicken, it would be great if i could say something like:

Code:
$r = new Restaurant();
$r->items->where('name', 'chicken');
$r->get();

internally, datamapper would execute the following CI's active record code:

Code:
$this->db->select('*');
$this->db->from('restaurants');
$this->db->join('items_restaurants', 'items_restaurants.id=restaurants.id');
$this->db->join('items', 'items.id=items_restaurants.id');
$this->db->where('items.name', 'chicken');

imho, this improvement is neccesary to insert datamapper into real world projects. i bet it will help us in the future.
#40

[eluser]steelaz[/eluser]
I agree with gusa, I had a similar problem with label->band->song setup and I ended up adding extra label->song relationship, so I could do $label->song->all instead of doing foreach loop.

Improvement that gusa is proposing would be very welcome.




Theme © iAndrew 2016 - Forum software by © MyBB