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 - 10-15-2008

[eluser]OverZealous[/eluser]
By parse, I meant "understand" - sorry, geekspeak. It's a very clean source code, and fairly well documented.

As far as your application design, I'm not sure that DataMapper is the correct choice for very fast updates. You might want to try to combine DataMapper (for the more constant elements, like user prefs and page information) with more traditional DB access routines (for the constantly changing info).

In all honesty, if this wasn't PHP I'd tell you to rely on an in-memory model for constantly changing values.

As far as checking data, what information is being sent that needs to be checked for security errors? Maybe you should look at your data model, and you can reduce the number or error checking rules.

For example, if you are storing a single text value (eg: 'attack'), maybe you should change this to a numbered array, and then you can validate just using intval().

If you are combining rules into one statement, maybe you can split it up into multiple fields (eg: 'attack:4:3' becomes 'attack', '4', and '3'). This, again, would allow you to check the data better.

Finally, xss_clean is only really needed for user input that is sent back to the browser AS html. If you are sending back plain text, you should be safe using strip_tags() or htmlspecialchars(), which is much faster.

In general, I recommend avoiding allowing user-entered HTML unless it is an internal application.


DataMapper 1.6.0 - El Forum - 10-15-2008

[eluser]ntheorist[/eluser]
hey i've got a general question about relational tables...

the way we're setting these up, we're creating multiple tables that relate one object to another.. and i've thought about how since each table name is unique and each primary key in that table is unique as well, any row in the database could then be identified by table/id, like an address.. couldn't I just create a single table called 'relations' or something, that would look like the following:

table: relations

id | table1 | id1 | table2 | id2

with an index of ('table1', 'id1') as index1 and ('table2', 'id2') as index2

perhaps even adding a varchar column at the end, allowing for a description of the relationship.

in your guys' opinion, do you think this would work, or could be considered good practice?

thx,

CC


DataMapper 1.6.0 - El Forum - 10-15-2008

[eluser]BaRzO[/eluser]
DataMapper Relation Types you can read here you'll find your answers Wink


DataMapper 1.6.0 - El Forum - 10-15-2008

[eluser]OverZealous[/eluser]
@commandercool
First, I should state that I am in no way associated with DM or CI - I'm just another user Tongue .

That being said, I know a thing or two about setting up databases. What you are describing would be a fairly inefficient way of storing information.

I realize that it looks bad having so many tables. (In fact, I myself prefer containing single-relationships within a table, so that NON-NULL relationships can be enforced.) However, the DB engine is designed to optimize table joins. It creates indexes based on lookup information, especially if you create your table correctly.

A table that has two related ids - and these ids are set as the primary key - can be indexed on the two columns. This means that, if the table gets big enough, the DB engine can almost immediately find rows based on one or both ids.

When you attempt to collect unrelated information, you ask the database to make more complex queries, and these queries become harder or impossible to optimize. In the case of a generic relations table, you are no longer representing the relationship within the database. This means that the final query now requires multiple lookups: once to get the related ids, and once to get the actual values.

If you look at the code for DM, you will notice that relationships are looked up using joins. These joins allow the database to gather the related values in one query, and in an optimized manner.

In general it's considered bad practice to store names of tables or names of fields within a table, because you've just abstracted the database. The purpose of the database, however, is to provide a structure for the information.

To learn more about database design, you can try starting at the Wikipedia article on Database Normalization.


DataMapper 1.6.0 - El Forum - 10-15-2008

[eluser]Boyz26[/eluser]
Hi, I just tried out the new dm library. I am using ng sessions now to manage my session, and it seems that both are them are not compatible, i think.
The sessions still work, but everytime when i use
Code:
$this->session->set_userdata('test','123');
with the error
Code:
Call to a member function set_userdata() on a non-object in /Users/ma/Desktop/localhost;8888/rebbelus/system_rebbelus/application/models/player.php on line 43
and on the webpage
Code:
Message: Cannot modify header information - headers already sent by (output started at /Users/ma/Desktop/localhost;8888/rebbelus/system_rebbelus/application/controllers/login.php:26)

Filename: libraries/Session.php

Line Number: 377
It points to this place when I view the error log:
Code:
function sess_write_cookie()
    {

        // save only session_id in database mode. But as array with key 'session-id' to maintain compatibility
        if ($this->use_database == TRUE)
        {
            $cookie_data = serialize(array('session_id' => $this->session_id));
        }
        else
        {
            $cookie_data = serialize($this->userdata);
        }

        if ($this->encryption == TRUE)
        {
            $cookie_data = $this->CI->encrypt->encode($cookie_data);
        }

        setcookie(
                    $this->sess_cookie,
                    $cookie_data,
                    $this->sess_length + time(),
                    $this->CI->config->item('cookie_path'),
                    $this->CI->config->item('cookie_domain'),
                    0
                );

    }



DataMapper 1.6.0 - El Forum - 10-15-2008

[eluser]OverZealous[/eluser]
You appear to have two separate issues.

1)
You cannot access the session object from within DataMapper models. They are not true CI models, and do not inherit most of the CI libraries.

If you want to access the session object from within your model (which, really, should be accessed from within the controller, and passed to the model if needed), you can get it like this:
Code:
// get the CodeIgniter engine
$CI =& get_instance();
$this->session = $CI->session;

Make sure that the session object was loaded already. Alternatively, add this to your DataMapper extension class (you are using one, right?)

2)
You definitely have something being sent to the browser before it should be. Usually this is caused by an errant piece of text at the top or bottom of the PHP file (probably your index.php). Sometimes it is caused by the Unicode BOM - a bit of hidden text used by text editors to determine the proper Unicode format.

This is usually what causies the "Cannot modify header information" error.

There's no quick fix for this, except to look around for text outside the <?php ?> blocks.


DataMapper 1.6.0 - El Forum - 10-15-2008

[eluser]Boyz26[/eluser]
All I did was
- copy in new dm library
- delete old dm model
- add 'datamapper' to autoload library and remove from autoload model

So i tried reverting and everything worked fine again.

Should I just stick to the old model? Will that be secure?

Thanks.


DataMapper 1.6.0 - El Forum - 10-15-2008

[eluser]OverZealous[/eluser]
I don't think there are security issues, but there is definitely feature changes and bug fixes between them.

Because the old design was based on each DataMapper class also being a Model class, they inherited a lot of cruft.

The best way to fix it, since I would guess the design is not moving back to the model format, is to subclass DataMapper, like I mentioned. Make a file called datamapperext.php. Put it in the models directory.

Put this inside that file (probably should comment it, etc):
Code:
class DataMapperExt extends DataMapper {
    function __construct() { // note: PHP5, use DataMapperExt on PHP4
        parent::__construct(); // PHP4 = parent::DataMapper()
        $CI =& get_instance();
        $this->session = $CI->session;
    }
}

Now, change all of your models from class My_model extends DataMapper to class My_model extends DataMapperExt. Then, change all of your constructors from parent:Big GrinataMapper() to parent:Big GrinataMapperExt (although I recommend using the PHP5 __construct() if you can).

Now you can add little features to DM, without ever having to worry about upgrade. Want to add a new validation function, but you use it in multiple classes? Add it to DataMapperExt. Same goes for additional methods. (I like having a get_by_id($id) method, for example.)

Also: Make sure you updated your relationship tables (has_many, has_one) to the new format (just list the model names, meaning 'model' => 'models' becomes just 'model'.


DataMapper 1.6.0 - El Forum - 10-15-2008

[eluser]ntheorist[/eluser]
[quote author="OverZealous.com" date="1224132588"]@commandercool
First, I should state that I am in no way associated with DM or CI - I'm just another user Tongue .

That being said, I know a thing or two about setting up databases. What you are describing would be a fairly inefficient way of storing information.

I realize that it looks bad having so many tables. (In fact, I myself prefer containing single-relationships within a table, so that NON-NULL relationships can be enforced.) However, the DB engine is designed to optimize table joins. It creates indexes based on lookup information, especially if you create your table correctly.

A table that has two related ids - and these ids are set as the primary key - can be indexed on the two columns. This means that, if the table gets big enough, the DB engine can almost immediately find rows based on one or both ids.

When you attempt to collect unrelated information, you ask the database to make more complex queries, and these queries become harder or impossible to optimize. In the case of a generic relations table, you are no longer representing the relationship within the database. This means that the final query now requires multiple lookups: once to get the related ids, and once to get the actual values.

If you look at the code for DM, you will notice that relationships are looked up using joins. These joins allow the database to gather the related values in one query, and in an optimized manner.

In general it's considered bad practice to store names of tables or names of fields within a table, because you've just abstracted the database. The purpose of the database, however, is to provide a structure for the information.

To learn more about database design, you can try starting at the Wikipedia article on Database Normalization.[/quote]

cool.. thanks for the thorough answer. heh, i've read through the wikipedia article a few times, not that i grasp everything yet in the terms it describes but i'm working on it.

right now i'm just wrangling with the best way to implement singular items in the database. Most notably, when storing files and photos. files (pdf, word docs, etc) and photos have separate tables, and each has its own model (which i can then add upload functionality to, etc)..

anyway, so say i have users, which can have a profile, which can in turn have a photo, then groups, which can have albums that have photos, and groups have users, which have a profile, photo etc.. you get the idea.. as well as other items, which could either have an album or photo. Although a photo isn't strictly related to either of them (beside albums). Thus, i have the tables:

photos_albums, photos_userprofiles, photos_groups, photos_users

then in the photos model:

Code:
$has_one = array('album');
$has_many = array('userprofile','group','user')

should that work then for photos that have no album? or only exists in a profile?.. will many relationships on an item like a photo create performance issues?

Also, for certain items, that say has one file, i can specify that in the has_one array, but i'm getting lost when trying to store a label for that (or config data), when producing a form for instance.. because the photos are generic but i want to be able to give it a specific purpose or name, depending on the item it's attached to. I'm attempting to put that information in the model validation array, but i think i'm just adding too much to the problem.

sorry if that all seems vague perhaps, and i'm not expecting anyone to solve my probs for me either.. i don't understand 100% how what i'm building will work but i have a vision of it. I guess right now i'm viewing it in terms of the logical problems i'm running into when adapting datamapper to a system that can handle datamaps dynamically. I want to be capable of creating in the controller something very simple like :

Code:
function add_user()
{
    $user = new User();
    //
    if($user->process_form()) // check all validation
    {
         $user->save_all(); // Handles file uploads, related item saves and saves the datamap itself
         redirect($redirect_page);
    }
    else
    {
         $user->print_form(); // print form elements, errors with values etc..
    }
}

i suppose it just gets complicated when dynamically handling related items in forms and during validation etc.. something i'll be working on surely over the next few weeks.

thx,

CC


DataMapper 1.6.0 - El Forum - 10-15-2008

[eluser]Boyz26[/eluser]
It worked! Thanks OverZealous!!