I'm getting my feet wet in OOP and have a question about __construct() content:
Suppose I want to make a PlayResult class, which will take protected ID,Date, and Winner properties. That would seem like logical things to put in the __construct() method, but the ID is the unique auto-incremented ID generated by MySQL when the play result is added to the table for the first time.
Now the ID is very important to my code, because that's how I keep track of individual records when they're being edited. However, obviously when a user uses an HTML form to submit a new play result there is no ID value because the result has not yet entered the database.
So, should the ID go in the constructor or not? Or should I construct with date and winner only, then set the ID if I have one?
Thanks :-)
Saving the object in the database is not the responsibility of the object (unless it's an ActiveRecord), but of a class on the persistence layer, for instance a Table Data Gateway. As such, the PlayResult class should not have to bother about the ID being set or not and be an optional field.
If you want the ID to be required in the object, you'd have to check if it exists in the database (cf. Repository or Identity Field). If not, create the new record in the database first, then create the object instance of the PlayResult with the newly created ID.
Related
Suppose I have an User, and a Transaction model on Laravel. It doesn't matter the properties, they only have in common an uuid and a name field
Now I want to create an Audit model which will take more or less the following fields:
id - The regular autoincrement id
ts - The timestamp when the action is performed
actor - The one who performs an action, its a reference to a user's id
verb - Which action is performing over a certain object
object - The object to which the action is performed
comment - whatever
So if an admin creates o updates a new user will produce an audit records like
1, 1/1/2021 00:00:01, 1, 'create', User, 'bla bla bla'
2, 1/1/2021 00:00:02, 1, 'update', User, 'reset password'
But that will also apply to other kind of records like the Transaction I mentioned before
Currently I'm storing the object's id, and based on the "verb" (or action), I know the kind of Object they were acting upon, and it works, but I'm experimenting if there are some other ways. My databases aren't huge, so performance is not an issue.
The best way to store an object like that in a database is in a normal form.
I'd suggest creating a new migration and model for your audit, and storing all the relevant information there.
However, you can serialize your object as a string if you don't have any performance concerns, or if the data structure is likely to change. A popular way of doing this is to use json_encode($your_obj).
I'm a Laravel noob rewriting some old code to Laravel.
I have a system for managing purchases and games and I'm writing the store method of the PurchaseController. The form for creating new purchases contains data about the purchase and an array with data about the games.
There is a many-to-many relationship between games and purchases: a purchase can contain many games and a game may be linked to multiple purchases.
The thing is that the game may already exist in the database. I want to do the following:
Insert the new purchase into the database (this part I got sorted out already ;))
Check if the POSTed name of the game already exists in the database.
If it exists, attach it to the newly inserted purchase. If it doesn't exist, insert it and attach it to the newly inserted purchase.
I don't want to update the game if it already exists in the database, just to attach it to the purchase.
I've looked into firstOrCreate but that doesn't do what I want. It checks on all the arguments you feed it, you can't just make it check only the name (this issue basically).
The undocumented method updateOrCreate does accept two arrays (one for attributes to check on, another for values to insert) but it updates the record if it exists, which is not what I want.
So, is there a nice, proper way to do this with Eloquent or do I simply need to manually write some code that checks if the game exists in the database and inserts the game unless that's the case?
EDIT:
It seems that this is possible with firstOrCreate after all in Laravel 5.3: https://github.com/laravel/framework/pull/13236
firstOrCreate is what you need, but you can feed it just the game name, then attach it to your purchase.
$game = Game::firstOrCreate(['name' => $gameName]);
$purchase = new Purchase(['otherArgs' => ...]);
$purchase->games()->attach($game);
I was probably overthinking this too much. The following code does what I want:
// Insert games (unless they exist) and attach to new purchase
foreach($request->games as $game) {
$gameModel = Game::firstOrNew(['name' => $game['name']]);
if(!$gameModel->exists) {
$gameModel->status_id = $game['status'];
$gameModel->note = $game['note'];
$gameModel->save();
}
$gameModel->purchases()->attach($purchase->id);
}
I just thought maybe there was a nicer/shorter way to do this.
Looking to make a class that will be for 'customers'. The purpose of this class is to pass in some details, and then either add a user or update an existing one.
After this, I might also want to do to more things with this 'customer'.
Im new to classes so need to know how to always refer to the same row no matter what i'm doing with the current initiated class.
Basic use:
$customer = new Customer($customer_details);
When creating a new instance of this class, I want it to straight away add / update a row.
However, as well as this later on I might want to update a specific field:
$customer->setValue('firstname','Craig');
But I dont want to have to do another lookup to get the row ID etc in this fucntion. I want $customer to always reference the user given the $customer_info.
Assuming you want setValue() to update the database, I would advise creating a field in your Customer class that contains the identifier for the row in the database.
/**
* Database identifier.
*
* #var string/int
*/
private $id;
Have your constructor set the value of the identifier on object creation using $this->id = $id. Then your setValue() call can use that identifier to update the information in the database.
EDIT
If you are creating a new Customer instead of updating an existing one (passing new data to the constructor) the database controller that you are using should have a means to get the ID of the new row (given it is an auto-incremented value). Otherwise the ID is something that you are generating, in which case you could just set the field value in the class.
I think you're referring to the Active Record Pattern. You can find many implementations in PHP, such as Propel.
Recently started working with OOP in PHP. Following the "code to an Interface" principle, i got confused as to the type hint to use when passing a single object or multiple as argument to a method.
Currently, i have a "Student" class - represents a row in my students table, i also have a "Students" class that holds multiple student objects in an array.
To fetch the profile of one student, i pass the Students object (holding a single student object) to the profile class. I set a Students type hint in the profile class.
Now i feel this is bad code as i have lines like this
student = new Students();
and students = new Students();
question is,
am i on the right path?
if i remove the Students class and work with Student alone, based on the principle, how do i pass multiple Student objects (assuming array) to the profile class if it accepts a Student type hint?
what options do i have?
Thanks.
If by Students you mean a collection of Student objects, perhaps a better name would be StudentCollection or StudentSet.
There are two ways around the type hint problem:
Introduce a method on StudentCollection called ->getProfiles(); it would return an array of profiles for each Student instance it's managing by calling methods on Profile.
Introduce a (static) method on Profile that operates on a StudentCollection instance.
The first option has feature envy, which is why I've included a workaround.
Instead of reinventing the wheel you might want to try Doctrine or at least take a look at its architecture.
I'm not sure if I get your exact issue... But if you want to go for your own code I would first abstract the DB layer as well and have some base classes like Database, Table, Row, Field that an describe the DB stack and extend them as needed with some magic methods. So when you do Student extends Table it would automatically check for a "students" table or whatever else convention you like to implement. Alternatively you could just pass the table name as arg.
Whatever Object is returning the result set from the database would have to construct a single Row object for each row and add it to a collection of rows that I would name ResultSet and contains all the row objects and return that collection.
Is it good to add new column in table WP_USER - Or - should I add stuff in metauser table?
I was questioning this because there is a WP function
/* Get full WP_User object instance. */
$user = new WP_User ($user->ID);
Will that work as well after adding column in WP_USER?
If you want custom fields to be added to your user, use the usermeta or create a new table with username as primary key. This would allow you to be future proof in terms of updates.
Ask yourself this: does the data I want to store have a 1-1 relationship with a user table entry? If so, put it in a separate table indexed by user ID (call it [prefix]_user_auxdata or something like that), and add other 1-1 data there, should the need arise again. If not, put it in usermeta as a key-value pair.
The reason to store it separately is because this future-proofs your database from changes WordPress may want to make to the users table. It avoids a potential conflict by eliminating the possibility of one in the first place.