ExpressionEngine CMS
Open, Free, Amazing

Thread

This is an archived forum and the content is probably no longer relevant, but is provided here for posterity.

The active forums are here.

DataMapper 1.6.0

September 05, 2008 12:32pm

Subscribe [115]
  • #166 / Oct 15, 2008 3:29pm

    Boyz26

    28 posts

    Hi I got the following error when I first run this page, but it becomes alright once you click submit on the form.

    A PHP Error was encountered
    
    Severity: Notice
    
    Message: Undefined property: stdClass::$error
    
    Filename: character/create.php
    
    Line Number: 49

    Here’s the controller

    function slot($slot)
        {
            $this->validation->set_error_delimiters('<div id="error">', '</div>');
            
            $rules['display_name']    = "xss_clean";
            $fields['display_name'] = 'Display Name';
            
            $this->validation->set_rules($rules);
            $this->validation->set_fields($fields);
            
            //list of classes
            $data['class'] = array('archer'=>'Archer', 'warrior'=>'Warior');
            
            //create character
            $display_name = $this->input->post('display_name');
            $c = '';
            
            switch($this->input->post('class'))
            {
                case 'archer':
                    $c = new Archer();
                    break;
                case 'warrior':
                    $c = new Warrior();
                    break; 
            }
            $c->display_name = $display_name;
            $c->hp = 100;
            $c->time_created = time();
                
            if ($this->validation->run() && $c->save())
            {
                echo "Character created!";
            }
            else
            {
                if (interface_exists($c->error)) {echo 'true'; } else { echo 'false';}
                $this->load->view('character/create_view', $data);
            }
        }

    The model:

    <?php
    class Archer extends DataMapper {
    
        var $has_many = array("archer_skill" => "archer_skills");
        var $has_one = array("battle" => "battles", 'player' => 'players');
        
        var $validation = array(
            array(
                'field' => 'display_name',
                'label' => 'Display Name',
                'rules' => array('trim', 'required', 'min_length' => 4, 'max_length' => 15, 'alpha_dash', 'unique')
                ),
        );
    
        function Archer()
        {
            parent::DataMapper();
        }
        
        
    }
    ?>

    I have tried different ways to check if $c->error->string is present but couldn’t find a way because it always has the same error of undefined stdclass.
    Is there any way to check if stdClass::$error is defined?

    Thank you!

  • #167 / Oct 15, 2008 3:45pm

    OverZealous

    1030 posts

    You aren’t setting $c.  You only set $c if it has a $class of ‘archer’ or ‘warrior’, but on initial page display it doesn’t have a class yet, so $c is actually a string (’‘).

    Also, I’m not sure why you are running CI’s validators when DataMapper automatically runs validation routines.  You can simply add ‘xss_clean’ to the validation routine inside the model.  It will run automatically on ->save() or if you call explicitly using ->validate().

  • #168 / Oct 15, 2008 4:16pm

    Boyz26

    28 posts

    My current dilemma is that if i use dm to do the xss validation, it will be a lot of overhead because i will be updating the database frequently.

    The same goes to the seperation of Archer() and Warrior(). I initially used one database Character() but decided that i could just split them to reduce resource usage.

    Is there any place you can point me to so that I can do more research or reading?

    Thank you!

  • #169 / Oct 15, 2008 5:04pm

    OverZealous

    1030 posts

    Did you read through the DataMapper docs on the first posting here?  They are very good.

    Also, the source code is pretty easy to parse.

    Finally, as far as validation, if you don’t change a field, then DataMapper doesn’t validate the field, or update it in the database, for that matter.

    If you are changing a field, then the xss_clean method probably should be called, anyway, since I doubt you’d be changing it without relying on some kind of user input.

    (How much updating are you talking about, anyway?  I mean, most modern servers can handle some processing.  Are you looking at hundreds of updates per minute?)

  • #170 / Oct 15, 2008 5:35pm

    Boyz26

    28 posts

    Also, the source code is pretty easy to parse.

    What do you mean by easy to parse?

    (How much updating are you talking about, anyway?  I mean, most modern servers can handle some processing.  Are you looking at hundreds of updates per minute?)

    I guess so. I am trying to make a game, so a user can be ‘attacking’, say, 10 times a minute. If there’s just 20 users doing so, then it’s already 200 updates on several tables. What kind of approach would you suggest to this situation?

    I have seperated controllers into single ones and put them into folders. Separated the table characters into tables for archers and warriors and more, so that searches and updates can be done faster (i think i read this somewhere).

  • #171 / Oct 15, 2008 5:51pm

    OverZealous

    1030 posts

    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.

  • #172 / Oct 15, 2008 8:11pm

    ntheorist

    84 posts

    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

  • #173 / Oct 15, 2008 8:48pm

    BaRzO

    105 posts

    DataMapper Relation Types you can read here you’ll find your answers 😉

  • #174 / Oct 15, 2008 8:49pm

    OverZealous

    1030 posts

    @commandercool
    First, I should state that I am in no way associated with DM or CI - I’m just another user 😛 .

    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.

  • #175 / Oct 15, 2008 8:57pm

    Boyz26

    28 posts

    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

    $this->session->set_userdata('test','123');

    with the error

    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

    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:

    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
                    );
    
        }
  • #176 / Oct 15, 2008 9:07pm

    OverZealous

    1030 posts

    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:

    // 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.

  • #177 / Oct 15, 2008 9:16pm

    Boyz26

    28 posts

    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.

  • #178 / Oct 15, 2008 9:39pm

    OverZealous

    1030 posts

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

    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::DataMapper() to parent::DataMapperExt (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’.

  • #179 / Oct 15, 2008 10:10pm

    ntheorist

    84 posts

    @commandercool
    First, I should state that I am in no way associated with DM or CI - I’m just another user 😛 .

    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.

    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:

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

    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

  • #180 / Oct 15, 2008 10:27pm

    Boyz26

    28 posts

    It worked! Thanks OverZealous!!

.(JavaScript must be enabled to view this email address)

ExpressionEngine News!

#eecms, #events, #releases