OOP in conjunction with any API/SQL - php

Currently I am combining two APIs and as I have done in former such projects, I create a 1-1 relation between the SQL Table rows and fields in an object.
But I am unsure how to get around it when dealing with an API that takes some information of an item and from this information provides new information that's attached to that very item.
Example in PHP:
class Cart {
public $cartItems, $reference;
public function __construct(array $cartItems, string $reference) {
$this->cartItems = $cartItems;
$this->reference = $reference;
}
}
Say an API (Alike Imaterialize) took a json_encoded version of this and would return a cart_id.
Question: What would be the best approach at this point? - Should one add an extra field to the Cart class or would one create another class that extended Cart with this extra field?
If Cart had an extra field that would get initialized only after the information was available, then how would one go about differentiating a Cart that had the ID and one that had not? - Sure one could create a boolean or any sort of function to keep track of it.
I find it hard to get my head around, but my best guess would be that what I am searching is a Design Pattern for this kind of interaction.
Thanks in advance.

Related

Laravel - Where to store statuses (flags)? Model, Class or config folder?

I need to extensively use statuses in mt project. I need them for my users (active, suspended, etc), an entity (active, pending_activation, inactive) and for my subscriptions(active, on_grace_period, not_subscribed, never_subscribed).
So far I thought that the best way is to store them in the DB but i have a feeling it's much easier to have them in the other 3 options.
I also thought that i can store them in my Eloquent Model as constants. For example my subscription model would look like this:
// SubscriptionModel
const SUBSCRIBED_ACTIVE = 1;
const SUBSCRIBED_ON_GRACE_PERIOD = 2;
const NOT_SUBSCRIBED = 3;
const NEVER_SUBSCRIBED = 4;
and retrieving them, for example in a blade view:
// subscription/index.blade.php
#if($user->subscription->status == /App/SubscriptionModel::SUBSCRIBED_ACTIVE)
<div>You are subscribed. Thank you</div>
#elseif($user->subscription->status == /App/SubscriptionModel::NEVER_SUBSCRIBED)
<div>You need to create a subscription before being granted full access!</div>
#elseif(...)
// and so on
How about doing the same but using the config folder and adding a file called status.php. Accessing it in the view would be like:
#if($user->subscription->status == Config::get('status.subscription.SUBSCRIBED_ACTIVE'))
<div>You are subscribed. Thank you</div>
#elseif(...)
// etc
Is there a better way?
Also, how about the other part of the equation, meaning the status stored in the DB. Should I only have a status column for the subscription table and store what the app dictates or even bettter create a separate table subscription_statuses and have a foreign_key subscription_status_id in the subscriptions table?
I tend to create a specific model for statuses, that acts as an enum. So if I have an Event model, I may have a corresponding EventStatus model that looks like this:
class EventStatus
{
public const CANCELLED = 'EventCancelled';
public const POSTPONED = 'EventPostponed';
public const RESCHEDULED = 'EventRescheduled';
public const SCHEDULED = 'EventScheduled';
}
I can then do checks like this:
$event->status === EventStatus::CANCELLED;
And I’ll usually add convenience methods to my models too:
class Event extends Model
{
public function isCancelled(): bool
{
return $this->status === EventStatus::CANCELLED;
}
}
For the “human-friendly” strings, I’ll then have a language file that has the text strings:
<?php // resources/lang/en/event_status.php
return [
EventStatus::CANCELLED => 'Cancelled',
EventStatus::POSTPONED => 'Postponed',
EventStatus::RESCHEDULED => 'Rescheduled',
EventStatus::SCHEDULED => 'Scheduled',
];
In my applications I do similar to #Martin Bean except I don't create separate classes for status, I store that inside the existent class/Model.
I'm going to call user, subscription and entity a entity.
Entity have a status that exists in it's Model and table in the database.
Each Model have constants of possible values of status like ACTIVE, INACTIVE, PENDING, etc, and those may vary for each Model.
Create methods for dealing with it like getStatusLabel(), listStatus(), isActive(), isX(), etc.
Those isActive/X() are only created if really necessary, maybe a Model have 4 status but you only do comparisons against one specific, so I'd create only one isX() for that status.
Example
class User
{
const STATUS_ACTIVE = 1;
const STATUS_SUSPENDED = 2;
const STATUS_INACTIVE = 3;
/**
* Return list of status codes and labels
* #return array
*/
public static function listStatus()
{
return [
self::STATUS_ACTIVE => 'Active',
self::STATUS_SUSPENDED => 'Suspended',
self::STATUS_INACTIVE => 'Inactive'
]
}
/**
* Returns label of actual status
* #param string
*/
public function statusLabel()
{
$list = self::listStatus();
// little validation here just in case someone mess things
// up and there's a ghost status saved in DB
return isset($list[$this->status])
? $list[$this->status]
: $this->status;
}
/**
* Some actions will happen only if it's active, so I have
* this method for making things easier.
* Other status doesn't have a specific method because
* I usually don't compare agains them
* #return Boolean
*/
public function isActive()
{
return $this->status == self::STATUS_ACTIVE;
}
}
I do not agree with the other answers. Your status information should be stored in the database. A well designed database should be clear and usable without the application. What happens if you decide to use this database to power something like a mobile application as well? You will be taking some of the information away from the database and storing it only in Laravel, meaning you would have to duplicate that list of statuses in your mobile application too, and maintain it across the two.
This kind of information should be stored in the database.
Option 1
If your users can only ever have one status, then you should use an enum field with the values subscribed, subscribed-grace, not-subscribed, never-subscribed
This is just as simple in your views:
#if($user->subscription->status == 'subscribed'
Option 2
If however, you might have multiple statuses, then you should almost certainly have a separate field for each status, and use a TINYINT to store a 1 or 0.
Separate status table?
I cannot see a good reason to use a separate status table unless you anticipate you might add many more statuses, and even if you are adding more, you can just add new values to the enum or add a new field depending on which option would suit.
A status table would be ideal if you plan to use the statuses for many other tables in the database besides users.
The only other reason for a seperate status table would be if you decided to change the meaning of a particular status. This would mean you could rename the status in the status table, but the users would still be linked to it via it's primary key. Changing the meaning of a status with the previous two methods would involve changes to the structure.
It really comes down to how you anticipate you will use them, but there is no reason not to keep them in the database.
There are advantages and disadvantages to each method. It's good to be aware of each.
Table - Pros and cons (AJReading's method):
Adding and maintaining a table SEEMS tedious
Just having another table and model can make our code feel more cluttered (not saying it's a good reason not to use just saying it's kinda true)
It gets awkward when we have application logic dependent upon something in the database (things in the database feel like they should be variable, when we base application logic on them they're required)
Now we have migrations, but before them these used to be the bane of developers existence (they would make switching between servers an awful chore because you had to remember to add new statuses or your app would crash)...you would have had to do this with any database change but still these were the ones I'd have to do the most frequently
Good for data integrity
Using constants: Pros/cons (Martin Bean's method):
Avoids the disadvantages above
These are easy to reference in your code and base logic on
You don't have to create a new model or table even (he does in his example, but you could also just put them in the Events model)
They're great for values that will ONLY be used behind the scenes
They reduce the amount of queries
They just don't feel like as much work. They seem easier to refactor.
Con: they get kinda awkward when you get into labeling them, retrieving all of them, getting descriptions, etc. The translation solution is a good one but if you don't use translations in your app then this is a bit awkward as well.
Ultimately they're breaking the ORM flow you have going. If all your other models extend Eloquent then this breaks the mold a bit.
There's no real agreement on how to best do this. A lot of people use a different method each time.
Like AJReading said, if you need to use the database alone for another aspect of the project it won't work
I use the constant method but sometimes I'd think my code might be cleaner and simpler if I'd used tables. It's a hard call. I'd like there to be a well documented solution for the constant method to at least create consistency but I haven't seen one yet. Either way I don't think there's a right or wrong answer. Pick one and go with it!
For decisions of this nature, ask yourself this:
"Will there ever be an instance of my application where it would make
sense for these constants to have different values?"
e.g. a test environment, some sort of clone, some not yet defined but possible future version...
If the answer to that question is "yes", then it should probably go in application config.
If it is unlikely, (or daft) to have the values change, they belong to, and should go in the model.
I suggest in this case there would be no sensible reason to ever have a version of the application with different values, so I'd put it in the model.

php class to serve properties of an object

I am new to PHP OOP (coded PHP in procedural style for some time now) and I think that I understood the SOLID principles and I understood that an object not necessarely is equal to an entity in a relational database. Anyway I have slight problems to apply this knowledge to this practical situation:
I want to write a class serving/handling product data which is attributes of products (like product name, weight, etc.) but als quantity on stock, open orders, next incoming shipment (with date and quantity being delivered) and so on.
This alone raises questions:
Does the plan to create one class to serve all this data interfere with the single responsibility principle (so is serving the quantity in stock another responsibility than serving the weight of the product)? In other words: Should I rather write an extra class for serving product attributes and another class to serve quantity in stock and another class to serve incoming shipments on this product? To explain: It can be, that external code accessing the object data of this class does not need all these information but just a part of it (e.g. either an attribute of the product or the next incoming shipments, but maybe the external code also needs both).
If I should write two different classes would they be totally seperate or should one extend the other? I personally do not see why one should extend the other as it can always be that only one of these two is needed, so why should I link them together then.
What I know from past experience is that the bottle neck of PHP applications very often is the number of queries you send to the database interface. If I divide everything in different classes, I have several database queries while I would only need two if I have it in one class.
Anyway if I write it in one class, I still have two queries while maybe the outside code needs only data that can be retrieved from one of these two queries. Should I put the two queries in two different methods and let the code outside of the class decide which methods should be executed and therefore decide which parts of the product data are available in the object? (This would be to save on resources and execution time.)
If I want to prevent that the outside code has to decide which methods to call to have the right data available should I better declare the properties to be private and have the magic __get function execute the necessary queries? I myself believe this is a dirty work around and I read somewhere that the magic __get function is rather a type of error handling if an outside code wants to access private properties.
Should I also add data manipulation methods to this class? I could add one for changing the static attributes of a product, but does it make sense to have a method in this class to change the quantity in orders? I think this would rather belong to an "orders" class than to a class of product data, right?
Here is some code snippet to illustriate, what I intend to do (in this case I wrote to serve all data by one class and let the outside code decide which method to call to have the right data available:
<?php
class productdata {
public $productID;
public $productname;
public $weight;
public $deliverytime;
public $deprecated;
public $openorderquantity;
public $stock;
public $opensupplierorders;
public function readproductdatafromDB() {
$db = new Db();
$safe_productID = $db->quote($this->productID);
$rows_get_productdata = $db->select("SELECT ...");
$error = $db -> error();
foreach ($rows_get_productdata as $row_get_productdata) {
$this -> productname = $row_get_productdata["productname"];
$this -> weight = $row_get_productdata["weight"];
$this -> deliverytime = $row_get_productdata["deliverytime"];
$this -> deprecated = $row_get_productdata["deprecated"];
$this -> openorderquantity = $row_get_productdata["openorderquantity"];
$this -> stock = $row_get_productdata["stock"];
}
}
public function readopensupplierordersfromDB () {
$db = new Db();
$safe_productID = $db->quote($this->productID);
$this->opensupplierorders = $db->select("SELECT ...");
$error = $db -> error();
}
} ?>
Please do not care about the DB calls I have a good DB wrapping class, I think.
When calling the class I would do:
<?php
$productdata = new productdata();
$productdata->productID = '123';
$productdata->readproductdatafromDB();
echo "The weight of the product is: " . $productdata->weight;
?>
I hope I am asking the right questions. Thank you very much in advance to help me with this.
Best Regards,
Benedikt.
First principles: design it right and worry about performance/optimisation if and when you encounter problems there.
So, product attributes are seperate from stock attributes, which are seperate but related to order atributes, which are seperate but related to supplier atributes, etc. Thus each type of information should be encapsulated into its own class: and yes this will mirror the noramalised database schema to a great extent.
In your code, you're mainly breaking the Single Responsibility principe. Your class is doing two things: managing the product information and managing your database connection/queries. That's the wrong way to do it.
You'll have a lot of duplicate code this way. Now you only have a Product entity. What if you have 50 of them? You'll have the same code in all 50 classes, not something you'll want to do. Have a look at the Repository pattern, which can help you for database interaction.
The correct way is to seperate these. Create a class for managing the connection and retrieving the data and a class Product, not ProductData, of which objects can be created with the data you receive from the database.
I'd suggest you have a look at some OOP frameworks first. Work with them, try and understand them and you'll understand these concepts a lot better so you can use them in your own projects.
Other than that, have a look at design patterns. The book Head First Design Patterns is an excellent introduction to understand design principles and patterns.

PHP, storing attributes.. Objects or values in array

I'm just starting out with a new project which has a product class. An object will represent a product.
Each product has any number of un-defined attributes (could be colour, could be foobar etc..). The product object will contain an array of either attribute objects:
class attr {
var type; // string, float, int etc..
var name; // the name
var value; // the value
...
(and then the product object has an array of these attr objects..)
OR should I store an array for each product:
class product {
var attributes = array('colour' => 'red', 'weight' => '11')
...
Obviously I can make the array 2d and store the attribute type if I needed to.
My main concern is that products may have 20 or so attributes and with lots of users to the site I'm creating this could use up loads of memory - is that right, or just a myth?
I'm just wondering if someone knows what the best practice is for this sort of thing.. the object method feels more right but feels a bit wasteful to me. Any suggestions/thoughts?
As a general advise I'm against early optimization, especially if that means turning your OO models into implicit (non-modeled concepts) things like arrays. While I don't know what is the context in which you will be using them, having attributes as first class citizens will allow you to delegate behavior to them if you need, leading to a much cleaner design IMO. From my point of view you will mainly benefit in using the first approach if you need to manipulate the attributes, their types, etc.
Having said that, there are lots of frameworks that use the array approach for dynamically populating an object by using arrays and the _get()/_set() magic methods. You may want to take a look for example at how Elgg handles the $attributes array of the ElggEntity class to see it working and get some ideas.
HTH
There is no best practice for that, AFAIK.
You have two options as described in Your question where each has its cos'n'pros. All it depends on is how/where the products and attributes will be stored - if it is in MySQL database still there shouldn't be a difference as You could fetch an array or an object from a DB.
If You are using classes for every simple thing, then use classes also for attributes, if You use classes only for the big objects, then use arrays. It is upon Your preference. There won't be any significant memory consumption difference when using classes or arrays and by no means while having 20 or so attributes.
If it was upon me, I'd go with classes and array of classes for attributes as it gives more advantages in the future should I need to extend the attributes some way.
If the Product class really needs to be flexible and accomodate an arbitrary number of attributes, I would be tempted to make use of __get and __set e.g.
class Product {
protected $attributes = array();
public function __get($name) {
if (array_key_exists($name, $this->attributes)) {
return $this->attributes[$name];
}
}
public function __set($name, $value) {
$this->attributes[$name] = $value;
}
}
$o = new Product();
$o->foo = 123;
var_dump($o->foo);
This would lend itself nicely to implementing ArrayAccess and other SPL iterator type classes in the future - if your solution required it.
I thinks it more important to considering how you are going to store them in you database. I guess that you want to have a search where you could say something like I want a RED HAT size 12 then you must be able to find all the products that have attributes that match this. This is all done on a database level. It would not be a good idea to load all products in PHP classes first and then search.
Once you get what you want to show (search result, overview page, details) then you load the full product class with attributes. Since its all text/numbers and probably not more then a 100 products at once, speed wise it wont matter what you choose in PHP. Do what you like best.
In your database it could matter (since there you always works with all the products). Make sure you seperate strings/numbers/bools etc and put the correct indexes or you could have a mayor performance drop.

Yii - Massive Assignment of a private field

TL;DR - How do I massively assign private fields in Yii?
Any Yii experts on StackOverflow? The YiiFramework forums didn't really help me out.
I've got a private field hired in my CActiveRecord model that is dependent on another relation jobCount. Basically, if there is at least one valid job (stored in another table) associated with that member, they are consider hired.
Conventionally, I would set hired in the afterFind method, but that would mean loading the relation every time. For the sake of saving database queries, I would only like to load the relation if hired is needed. So I set hired to private, and can load the relation and set it once getHired() is called.
So far so good...
The problem arises once I incorporate the hired field in my CGridView. I'd like to be able to use the column filters, with a simple dropdown filtering on Yes or No. Upon filling out your filters, CGridView passes back a GET request, which you would set to a cleared model using massive assignment...
$model->attributes = $_GET['ModelName'];
Obviously I would like hired to get set as well, despite it being a private field. (I handle the searching for CGridView, don't worry about that.) I've made it a safe field in my model, but it doesn't get set.
setHired() function doesn't get called
setAttribute() function doesn't get called
setAttributes() function doesn't get called
What's the correct way to do this? Clearly, I could just add an extra line in my controller action...
if (isset($_GET['ModelName']['hired']))
$model->setHired($_GET['ModelName']['hired']);
...but I would really rather learn how to allow private fields to be massively assigned.
I realize that this is rather convoluted. If you see some way that I could streamline this hired bit, I'd appreciate that. Still, I would like to learn if there's a way to do this.
I suppose, you need just to add your attribute to the list of attributes.
public function attributeNames()
{
$names = parent::attributeNames();
$names[] = 'hired';
return $names;
}

Calculating data fom DB with CodeIgniter

i use a simple PHP framework (like Codeigniter) without ORM.
I have a database with product data (prices, sells, page in catalog...).
And i want to calculate the conversion per page and the conversion per product.
The calculations with SQL are not a problem, but i don't really know where to put them in.
Should I create a "Page" and a "Products" model with methods like
"Page::getConversions($page_id)" or a "ConversionPerPage" and a "ConversionPerProduct" model, or sth. completely other.
I think that the best model classes are to have two classes for each table - one for object and plural for static classes.
For example: if you have Page table then you should have Page and Pages classes.
First one will allow you to have one object from table and you can do the regular methods on it like:
$page = new Page($page_id);
$conversions = $page->getConversions();
$page_number = $page->getNumberInBook(); etc
On the other hand in Pages class you can put the methods that will (usually) return the array of Page and those methods will usually be static:
$pages = Pages::getPagesByCatalog($catalog_id);
This way you will have real OOP and code complete with full model MVC implementation.
I hope that this model hierarchy will help you. We are using it in our office and it showed to be really good.
All the best!
Basically, you create models based on the database schema. So, first option is preferred. Moreover, it should be instance method instead of class method (the object is then identified from the $page_id).
Presumably you are going to have Page and Product models anyway so I would add the getConversions() function to those.

Categories