PHP Object creation Looping - php

I have a class to manipulate orders. I have created multiple methods for each purpose too. There can be multiple orders to process which is generated from db. Right now, what I am doing is that, loop through each order and create objects with order id as param to constructor.
foreach($order_row as $order_rows)
{
$order_id=$order_rows->order_id ;
$warehouse =new WarehouseManager($order_id);
$warehouse->ProcessWarehouse();
}
Is it okay to loop like this? Is there any better way to handle this?

You don't need to create new object for each order. What if there is a huge number of records returned?, You only need to create one object to process an order one by one.
$warehouse = new WarehouseManager();
foreach($order_row as $order_rows)
{
$order_id=$order_rows->order_id ;
$warehouse->setOrder($order_id); // this method should be implemented first
$warehouse->ProcessWarehouse();
}

Related

php create fixtures with automatic relations

I'm currently looking into fixtures for a website with a lot of relations between data.
Let's say there is a league table which is in relation with teams table which is in relation with members table. I briefly checked Alice library to handle data "randomization" and other stuff.
But I have a question whether there is a library (or way), that would allow me to create "dependent" fixtures?
For example I would set template for league to automatically create 20 teams where each team would automatically create 10 members based on some defined structure.
Whenever I call create league fixture, it would create all the dependencies.
As mentioned in the official documentation you can have object references in your fixtures
$userAdmin = new User();
$userAdmin->setUsername('admin');
$userAdmin->setPassword('test');
$manager->persist($userAdmin);
$manager->flush();
$this->addReference('admin-user', $userAdmin);
// in another fixture
$userGroupAdmin = new UserGroup();
$userGroupAdmin->setUser($this->getReference('admin-user'));
Like Flask wrote above, use Doctrine DataFixtures.
Save yourself time and avoid Alice Bundle / library. I used it on a project in beginning, but had to remove it soon. You simply do not have enough control over generated data.
For example you want 3 random players in a team, everything okay, but there is no way to say that they must be unique. At least that was one of the scenarios I had most problems with.
But yes, use faker library.
Another advice that I would give you, implement something like a ->initSeed() method in each of your Fixtures class, which you call at the beginning of the ->load() method. It will call something like this:
$this->faker->seed(100);
Also make your fixtures implement OrderedFixtureInterface, so you have control what is inserted first. Here's the catch... you implement the initSeed() inside load(), NOT inside constructor, because constructor is called in the beginning on all classes, because getOrder() method is needed to find out priority. This way if you add another randomized property at the end of fixture file, the file which comes next, will still generate the same data, so fixture files will not be dependant between themselves.
If you need any code example, let me know, I can help.
Code for saving references:
In the LoadTeamData fixture class, have a constant:
const NUM = 10;
So, you can access it in other fixture file.
When you generate teams in a for loop, use index $i to save the reference.
// Generate teams
for ($i=0; $i<self::NUM; $i++) {
$team = new Team();
// ... set things
$this->setReference('team-'.$i, $team)
$manager->persist($team);
}
$manager->flush();
Then inside LoadPlayerData for example:
// For each team, generate some players
for ($t=0; $t<LoadTeamData::NUM; $t++) {
$team = $this->getReference('team-'.$t);
for ($i=0; $i<self::NUM; $i++) {
$player = new Player($team);
// ... set things
$manager->persist($player);
}
}
$manager->flush();

Grouping filters in Propel

I currently have a Propel based query that looks like this:
$product = ProductQuery::create()
->filterByLive(1)
->filterByApproved(1)
->findOneByFilename($filename);
I regularly use this query and instead of having to chain the two filters I wondered whether it's possible to create a new filter that encapsulates them? This means that if I were to add an additional filter in future then I could simply do it in this single method rather than having to go through the entire project adding the new filter.
For example:
$product = ProductQuery::create()
->filterByIsActive()
->findOneByFilename($filename);
Is this possible?
You can create needed method in your ProductQuery:
public function filterByIsActive()
{
return $this
->filterByLive(1)
->filterByApproved(1);
}
Propel generates this file only once and you can put any code you like inside this class - and it will not be overwritten.

proper way of using output of one class in another class

I am using the following code to produce an array:
// Create new customer object
$customers = new customers;
// Array of user ids
$customers->ids = array(34,23,78);
// Process customers
$customers->processCustomers();
The above code will output an array full of needed user information based on the users passed to it.
Now I need to take further action to this new customer array in the following code:
// Create new parsing object
$parseCustomers = new parse;
// Array of customer data
$parseCustomers->customers = ???????????
// Finalize new transaction
$parseCustomers->finalizeTransaction();
I need to pass the array from the first class output into the second and I'm wondering what best practice is.
This customer array can be very large at times, so ideally I wouldn't have 2 variables containing the same array at any time.
If you mean the processed array from the $customers object, you need some public method to get that data.
Let's assume you have a public method getData(). Your code would then look like this...
// Create new parsing object
$parseCustomers = new parse;
// Array of customer data
$parseCustomers->customers = $customers->getData();
// Finalize new transaction
$parseCustomers->finalizeTransaction();
There are several different ways you can handle this. Here are two:
You could return the MySQL result set from your class. I would run your query with mysql_unbuffered_query() so that it only uses up memory as you need the records.
When you grab your results, you could pass in your customers by reference:
Here's the code for #2:
// Create new parsing object
$parseCustomers = new parse;
// Array of customer data (not needed)
// $parseCustomers->customers = ???????????
// Finalize new transaction
$parseCustomers->finalizeTransaction($arrCustomers);
And your function declaration would change to this:
function finalsizeTransaction(&$arrCustomers) {
// Do your processing
}
This would allow you to use the ONE array of customers, eliminating your duplication. If you're dealing with really large data sets, so much that it could cause PHP to error out when it runs out of memory, I would use the unbuffered query method.
Hope that helps!

Reduce database calls for php web shop

I'm looking for a way to prevent repeated calls to the database if the item in question has already been loaded previously. The reason is that we have a lot of different areas that show popular items, latest releases, top rated etc. and sometimes it happens that one item appears in multiple lists on the same page.
I wonder if it's possible to save the object instance in a static array associated with the class and then check if the data is actually in there yet, but then how do I point the new instance to the existing one?
Here's a draft of my idea:
$baseball = new Item($idOfTheBaseballItem);
$baseballAgain = new Item($idOfTheBaseballItem);
class Item
{
static $arrItems = array();
function __construct($id) {
if(in_array($id, self::arrItems)){
// Point this instance to the object in self::arrItems[$id]
// But how?
}
else {
// Call the database
self::arrItems[id] = $this;
}
}
}
If you have any other ideas or you just think I'm totally nuts, let me know.
You should know that static variables only exist in the page they were created, meaning 2 users that load the same page and get served the same script still exist as 2 different memory spaces.
You should consider caching results, take a look at code igniter database caching
What you are trying to achieve is similar to a singleton factory
$baseball = getItem($idOfTheBaseballItem);
$baseballAgain =getItem($idOfTheBaseballItem);
function getItem($id){
static $items=array();
if(!isset($items[$id])$items[$id]=new Item($id);
return $items[$id];
}
class Item{
// this stays the same
}
P.S. Also take a look at memcache. A very simple way to remove database load is to create a /cache/ directory and save database results there for a few minutes or until you deem the data old (this can be done in a number of ways, but most approaches are time based)
You can't directly replace "this" in constructor. Instead, prepare a static function like "getById($id)" that returns object from list.
And as stated above: this will work only per page load.

Getting database values into objects

The thing is that you have classes and then you have the database data. When you create an object how do you set the objects properties to contain the data in the database ?
I saw something like this and I'm wondering if this is really the best way to do it. I'm sure this is a fairly common issue, but I don't know what are the most accepted solutions on how to handle it.
In this example when the object is created you pass an id as a parameter and then you run a query to the database with the id and you assing the returned values to the object properties. I don't have much PHP experience and haven't seen this used much.
Is this an acceptable way to achieve this purpose ? Is there a better or more accepted way ?
public function __construct($id = null){
if($id != null){
$sql = "SELECT *
FROM users
WHERE user_id = $id";
$res = Db::returnRow($sql);
// $res contains an associative array with database columns and values
if($res){
$this->user_id = $res['user_id'];
$this->user_name = $res['user_name'];
//and so on...
}
}
}
Could somebody provide some sample code or pseudocode to illustrate what is the correct way to do this ?
It could be an acceptable way for a homework maybe. But architecturaly it is not.
Your class that is representing your business data (a user in your example) must be loosely coupled with your database access logic. In the end the PHP class acting as a user should not be aware that the data come from a database, a file or any other resource. Following that you will be able to reuse your user php class in other projects without having to change anything to it! If you have your data access logic inside it you are stuck.
Conclusion: I would suggest to read some resources on Design Pattern (in your situation take a look at DAO pattern) ;) Hint: the one from Head First series is extremely accessible and enjoyable.
You could create a function to do this for you automatically, by looping over the associative array's key/value pairs. Or you could look into using an ORM library.
Yes, you can semi-automate this by having a parent class all objects inherit from. On load, it queries, "SHOW FIELDS FROM [my tablename]" and populates an associative array with the names. If an id has been passed in, it looks for a valid object in that table with that id and assigns the values to the array.
Side note: don't pass your id directly into your query like that. Parametize the sql and wrap a function around any user input to sanitize it.
If it's mysql, you can just do:
$obj = mysql_fetch_object($query);
PDO the ability to use arbitrary classes as the target for a fetch, but beware that they assign the variable data before running the constructor:
$pdo->query($stmt, PDO::FETCH_CLASS, "MyClass", array('foo'=>'bar'));
...where the final parameter contains arguments for your class constructor.

Categories