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

[eluser]MeanStudios[/eluser]
Got a self reference question for someone. I'm a bit confused when it comes to the DMZ way of doing self references since there is no example, I thrive on examples haha. I have a table to keeps track of quotes that are sent out to clients. My client wants to keep track of revisions made to a quote so when it's sent again, all the changes are highlighted in red on the auto-generated pdf I'm creating from the data in the quote. What I'm trying to do is just keep all those revisions in the same table as the quote they are related. How would I set up my model to make this happen? Currently the fields I have in the quotes table are:
id,
client_id, <--- the client this quote is related to
date,
data, <--- Quote data serialized to fit into one field
type <--- Type of quote it is, there are currently two types, Client and Diary.

My current model is very simple:
Code:
class Quote extends DataMapper {

    var $table = 'quotes';
    var $model = 'quote';
    var $has_one = array('client', 'order');

    /**
     * Constructor
     *
     * Initialize DataMapper.
     */
    function Quote()
    {
        parent::DataMapper();
    }

    function data()
    {
        $q = new Quote();
        $q->where('id', $this->id)->get();
        
        return unserialize(stripslashes($q->data));
    }
}

Any help would be a hugely appreciated!
#42

[eluser]OverZealous[/eluser]
@MeanStudio
There are some examples in the include RTF file. I know they aren't great, but they should help.

Now, as for your question, I'm not sure what you are asking. What item do you want to relate o itself?

As far as I can tell, there is no relationship going on. I think simply storing each version in the DB with a $has_many relationship, along with a version #, would be enough, then diff (or whatever) your changes. There's no need for self references. To get the latest version, just query
Code:
$client->quote->order_by('version', 'DESC')->get(1);
// although, this might work, if you don't need version numbers:
$client->quote->order_by('id', 'DESC')->get(1);

If you really want to store the history as a self-reference, you would write something like this:
Code:
class Quote extends DataMapper {
    $has_many = array(
        'quote_history' => array(
            'class' => 'quote',
            'other_field' => 'current_quote'
        )
    );

    $has_one = array(
        'current_quote' => array(
            'class' => 'quote',
            'other_field' => 'quote_history'
        ),
        'client'
    );
}

You can store the relationship wither on quotes, as current_quote_id (highly recommended), or in a dedicated current_quotes_quote_histories table, which current_quote_id and quote_history_id columns. Obviously

You'll still probably want to keep track of a version number, or use something like DataMapper's automatic created_on or updated_on column.

PS: Why would you serialize your quote data? It's not searchable (via the DB) that way. It's usually far better to store the data in multiple columns, so it is searchable, unless the data is binary, or would never need to be searched. Since you are looking at storing a versioned history, I think being searchable would be very useful. Just an opinion / question, and I'm sure you have a good reason!
#43

[eluser]MeanStudios[/eluser]
Yes, you do have examples, but there was no example for the self reference part. You just said use the same as above and there were two different example sets and I wasn't sure which one to use heh.

Basically, if I query for a quote ID, I want it to pull up the latest revision of that quote ID. I'm not too sure about the 'other_field' part of that array. Is that the name of the fields I have to make in the quotes table? Or would I make the fields 'current_quote_id' and 'quote_history_id'?

I'm serializing the data because each quote type has different named fields and they don't need to be searchable. I'd rather not have to make a different table for each quote type Smile. Also, this was a lot quicker haha.

My thinking is this. My client enters in a quote for their client and sends it to them through email with the attached populated pdf. It notates that it sent that particular version of the quote. The client doesn't like it and asks for it to be revised. So my client goes back and updates it but forgets something so they update it again and then once more. This last time they sent it back to the client. I want it to take the difference of the quote that was first sent and the one that was just sent marking all the data in red that have changed. This means that it just can't take the latest version and one version back to make the difference.

Complicated enough? heh
#44

[eluser]NachoF[/eluser]
I keep reading about these "self references"... sorry to ask such a n00b question but what are they and when would be a good time to use them??.... Im trying to learn as much as I can cause I have been hired to make a project (and its pretty much done already) but if I want to stay in this business for more future projects I guess I have to learn more and more still... (I still pretty much suck at HTML+CSS as well.)
#45

[eluser]OverZealous[/eluser]
'other_field' defines the reciprocal relationship field. It's clearer if they are not self-related:
Code:
"          User        Post
   ------------        -------
   created_post  <--&gt;  creator
    edited_post  <--&gt;  editor         "

In this example, to get the creator of a Post, you use $post->creator. To get posts that a user has created, you use $user->created_post.

So, on User, the 'created_post' relationship has two properties:
* 'class' => 'post' : this is the class name of the model we are relating to, since it isn't 'created_post'
* 'other_field' => 'creator' : this is the field as viewed by Post. We have to have it, or we can't make queries work.

On Post, the fields are:
* 'class' => 'user'
* 'other_field' => 'creates_post'

Notice how they are just opposites.

Now, as to your problem, you are making it way more complicated than necessary. Add a boolean field called 'sent', then just set that if it is sent.

To get latest sent version:
Code:
$client->quote->where('sent', TRUE)->order_by('id', 'DESC')->get(1);
#46

[eluser]OverZealous[/eluser]
[quote author="NachoF" date="1241685205"]I keep reading about these "self references"... sorry to ask such a n00b question but what are they and when would be a good time to use them??.... Im trying to learn as much as I can cause I have been hired to make a project (and its pretty much done already) but if I want to stay in this business for more future projects I guess I have to learn more and more still... (I still pretty much suck at HTML+CSS as well.)[/quote]

A self reference refers to when an item must store a reference to another item of the same type. Think of a file hierarchy. A folder can contain files, but it also can contain other folders. The relationship between two folders would be a self reference.

Other common self references:
* An Employee has a Boss (who is also an Employee).
* An Article is related to other similar Articles.
* A Bugfix depends on other Bugfixes before it can be completed.

Generally speaking, self references should be avoided unless they describe something that is recursive. In the case of MeanStudios' problem, I don't think it is actually recursive.

What makes them special, specifically for DataMapper, is (1) that they use the same table to store data, and (2) that they would have the same name on both sides of the relationship. Luckily, most relationships have a non-uniform connection, meaning, Parent->Child or Boss->Employee has a different meaning in each direction.

However, in the example of Article<->Article, the direction of the relationship does not matter. This is not something that can be described easily in a Database, and DMZ does not provide any tools for this kind of relationship. The best you can do is either modify it so it can be defined in unidirectional manner, or save the relationship twice, once for each direction.

In the original DataMapper, the only way to have something like a self-reference was to have two different models, which broke a lot of things. In DMZ, I let you specify all of the relationship fields manually (which is why they are a little confusing), so you can create very complicated relationships.

I don't know what your education background is, but if you can, I recommend taking a class on relational database management, since much of data storage is based on that. If a class isn't possible, try looking for books in your local Library. I find data storage to be difficult to learn without being hands-on.
#47

[eluser]NachoF[/eluser]
[quote author="OverZealous.com" date="1241686440"][quote author="NachoF" date="1241685205"]I keep reading about these "self references"... sorry to ask such a n00b question but what are they and when would be a good time to use them??.... Im trying to learn as much as I can cause I have been hired to make a project (and its pretty much done already) but if I want to stay in this business for more future projects I guess I have to learn more and more still... (I still pretty much suck at HTML+CSS as well.)[/quote]

A self reference refers to when an item must store a reference to another item of the same type. Think of a file hierarchy. A folder can contain files, but it also can contain other folders. The relationship between two folders would be a self reference.

Other common self references:
* An Employee has a Boss (who is also an Employee).
* An Article is related to other similar Articles.
* A Bugfix depends on other Bugfixes before it can be completed.

Generally speaking, self references should be avoided unless they describe something that is recursive. In the case of MeanStudios' problem, I don't think it is actually recursive.

What makes them special, specifically for DataMapper, is (1) that they use the same table to store data, and (2) that they would have the same name on both sides of the relationship. Luckily, most relationships have a non-uniform connection, meaning, Parent->Child or Boss->Employee has a different meaning in each direction.

However, in the example of Article<->Article, the direction of the relationship does not matter. This is not something that can be described easily in a Database, and DMZ does not provide any tools for this kind of relationship. The best you can do is either modify it so it can be defined in unidirectional manner, or save the relationship twice, once for each direction.

In the original DataMapper, the only way to have something like a self-reference was to have two different models, which broke a lot of things. In DMZ, I let you specify all of the relationship fields manually (which is why they are a little confusing), so you can create very complicated relationships.

I don't know what your education background is, but if you can, I recommend taking a class on relational database management, since much of data storage is based on that. If a class isn't possible, try looking for books in your local Library. I find data storage to be difficult to learn without being hands-on.[/quote]
Im studying "Systems Engineering" but its really more about management and costs than actually learning about good programming practices... I live in Venezuela and my college is pretty much for students of the far right that are formed to just be managers and not really part of the workforce... but I personally am very interested in how to get things done and not just being a project manager..... back to the topic though, so "self-referencing" is like hierarchy when it comes to classes in OOP???.. please elaborate more in your first example... say I have employees and a boss... how would I structure a sql database to have them all in the same table?.....
Edit:
Thinking about it a little more Im guessing the employee table would have a field "boss_id" that would actually be the employee_id that is the boss of that employee, right?... and the actual boss would just have himself or null, right?
#48

[eluser]MeanStudios[/eluser]
Okay, that clears things up Smile. Thanks!
#49

[eluser]OverZealous[/eluser]
FYI: I charge $100/hour for consultation ;-P

There are a lot of different ways to handle it. Most likely, it will involve having a single table that looks something like this:
Code:
"
id | name        | job         | supervisor_id
---+-------------+-------------+----------------
1  | John Smith  | CEO         | NULL
2  | Susan Jones | VP of Finan…| 1
3  | Joe Bloe    | Employee    | 2
"

In this example, there is only one supervisor/boss per employee. If you want multiple bosses (e.g.: like Office Space), that requires a dedicated table for tracking those relationships.

My DataMapper model might look like this:
Code:
class Employee extends DataMapper {
    $has_one = array(
        // This employee's supervisor
        'supervisor' => array(
            'class' => 'employee'
        )
        // This could also be specified in shorthand as
        // 'supervisor' => 'employee', but I don't recommend that
    );

    $has_many = array(
        // This employee's sub-employees.
        // note that, since 'class' is the same as the related field,
        // you don't need to specify it.
        'employee' => array(
            'other_field' => 'supervisor'
        )
    );
}

This relationship is a little different, because I wanted to have $boss->employee list all of the employees for the Employee $boss. (I needed to show this, so I'm sorry if it is confusing.) Because of this, you'll notice there is less fields specified.

Now let's add a new employee, and insert her between Susan and Joe (we always can use more middle managers, right? ;-) ):
Code:
$jane = new Employee();
$jane->name = "Jane Doe";
$jane->job = "Middle Manager";

$susan = new Employee();
$susan->get_by_id(2);

$joe = new Employee();
$joe->get_by_id(3);

// Save Jane, AND the relationships, all at once.
$jane->save(array(
    'supervisor' => $susan,
    'employee' => $joe
));
// note that $jane will overwrite $susan for $joe, so we don't need to delete that relationship!

Now, to get the supervisor or employees of a person, it's very simple:
Code:
$susan = $jane->supervisor->get();
$employees = $jane->employee->get();

If you want to see if you are at the head honcho, you could try:
Code:
$head_honcho = ! $person->supervisor->get()->exists();

One final example. Say you didn't want to use Employee->employee, you might have something like this:
Code:
class Employee extends DataMapper {
    $has_one = array(
        // This employee's supervisor
        'supervisor' => array(
            'class' => 'employee',
            'other_field' => 'subordinate'
        )
    );

    $has_many = array(
        // This employee's subordinates.
        'subordinate' => array(
            'class' => 'employee',
            'other_field' => 'supervisor'
        )
    );
}

Everything else stays the same!
#50

[eluser]NachoF[/eluser]
[quote author="OverZealous.com" date="1241689743"]FYI: I charge $100/hour for consultation ;-P

There are a lot of different ways to handle it. Most likely, it will involve having a single table that looks something like this:
Code:
"
id | name        | job         | supervisor_id
---+-------------+-------------+----------------
1  | John Smith  | CEO         | NULL
2  | Susan Jones | VP of Finan…| 1
3  | Joe Bloe    | Employee    | 2
"

In this example, there is only one supervisor/boss per employee. If you want multiple bosses (e.g.: like Office Space), that requires a dedicated table for tracking those relationships.

My DataMapper model might look like this:
Code:
class Employee extends DataMapper {
    $has_one = array(
        // This employee's supervisor
        'supervisor' => array(
            'class' => 'employee'
        )
        // This could also be specified in shorthand as
        // 'supervisor' => 'employee', but I don't recommend that
    );

    $has_many = array(
        // This employee's sub-employees.
        // note that, since 'class' is the same as the related field,
        // you don't need to specify it.
        'employee' => array(
            'other_field' => 'supervisor'
        )
    );
}

This relationship is a little different, because I wanted to have $boss->employee list all of the employees for the Employee $boss. (I needed to show this, so I'm sorry if it is confusing.) Because of this, you'll notice there is less fields specified.

Now let's add a new employee, and insert her between Susan and Joe (we always can use more middle managers, right? ;-) ):
Code:
$jane = new Employee();
$jane->name = "Jane Doe";
$jane->job = "Middle Manager";

$susan = new Employee();
$susan->get_by_id(2);

$joe = new Employee();
$joe->get_by_id(3);

// Save Jane, AND the relationships, all at once.
$jane->save(array(
    'supervisor' => $susan,
    'employee' => $joe
));
// note that $jane will overwrite $susan for $joe, so we don't need to delete that relationship!

Now, to get the supervisor or employees of a person, it's very simple:
Code:
$susan = $jane->supervisor->get();
$employees = $jane->employee->get();

If you want to see if you are at the head honcho, you could try:
Code:
$head_honcho = ! $person->supervisor->get()->exists();

One final example. Say you didn't want to use Employee->employee, you might have something like this:
Code:
class Employee extends DataMapper {
    $has_one = array(
        // This employee's supervisor
        'supervisor' => array(
            'class' => 'employee',
            'other_field' => 'subordinate'
        )
    );

    $has_many = array(
        // This employee's subordinates.
        'subordinate' => array(
            'class' => 'employee',
            'other_field' => 'supervisor'
        )
    );
}

Everything else stays the same![/quote]
Gee, thanks for all those examples... Im gonna try to dissect them all to understand it all fully..... from now on I wont ask as much and try to find out by myself... dont really have those 100$ lol... thanks for everything man.




Theme © iAndrew 2016 - Forum software by © MyBB