I want to make a program that pulls objects from a sql database and processes the objects against a set of functions before returning the data to the user.
It will work like this:
User specifies a date range in a javascript form.
The date range is sent to a php file on the server that converts it to
a sql query.
The sql query pulls all data in the database that matches the date
range, and stores each matching item and its associated information as a php
class in a temporary php file (see example below).
The main php program then processes each class in the temporary php file against a set of functions and returns the information to the user.
Example temporary php file:
class ice_cream
{
$temperature = 0;
$texture = 'soft';
}
class hard_candy
{
$temperature = 20;
texture = 'hard';
}
Example of Functions to process the classes against:
function will_it_break_dentures($class_name)
{
//$class_name is passed to the function based on the classes available in temp file
$food_type_class = new $class_name();
$damage_potential_temperature = $food_type_class->temperature;
$damage_potential_temperature = $food_type_class->texture;
if($damage_potential_temperature >= 15) && ($damage_potential_texture === 'hard')
{
print("Don't eat it");
}
}
Is there a more efficient/secure way to pull data from a database and process it against a set of functions? Is this the standard way to pull data from a database for processing? Item #3 seems suspect, but it's the best I could come up with. Any relevant informational resources on best practice are appreciated.
Your class definition should define the properties of the object, not the values. It should be defined statically, not dynamically at runtime. At runtime you create instances of this class and populate the data for each instance.
Try something like this:
class Food {
var $name;
var $temp;
var $texture;
// Constructor
public function food($name, $temp, $texture) {
$this->name = $name;
$this->temp = $temp;
$this->texture = $texture;
}
public function breaksDentures() {
if($this->temp >= 15) && ($this->texture === 'hard')
return true;
else
return false;
}
}
And use it like this:
function processFoods($daterange) {
$query = build_query_from_daterange($daterange);
$result = mysql_query($query);
while($row = mysql_fetch_assoc($result)) {
$food = new Food($row['name'], $row['temp'], $row['texture']);
// Now $food is an instance of the Food class populate with the values
// from the db, e.g., 'ice cream', 0, 'hard'.
if $food->breaksDentures() {
print("Don't eat it");
}
}
}
P.S. You may want to brush up on your object-oriented concepts. Your question is a good one but indicates some confusion about OO basics.
Related
Using PHP 5.6, and will be moving to 7.0 within next 12-18 months on this particular application.
So we have a quite large global config file -- which holds by now close to 100 variables (and each update gets more). As you would expect, this config file is called by every script page in the app, but not all config values are used in all cases -- but for convenience sake, we house them all in the same file.
But I was thinking that perhaps housing the values into functions would be more efficient, but as I am not an architect of the PHP language (or any language), I don't know if using functions is more efficient, less efficient, or pretty much no difference.
So here is an example scenario. In our config file, we have something like this:
$g['user']['enable_username_change'] = true;
$g['user']['enable_image_change'] = true;
$g['user']['display'] = "[LASTNAME], [FIRSTNAME]";
$g['user']['sort_by'] = "[LASTNAME]";
$g['user']['default_locale'] = "english";
$g['user']['profile_page'] = file_get_contents('profile_template.html');
These values are available to all scripts, but only a handful need them. Obviously we access them by just doing something like this:
if ( $g['user']['enable_username_change'] == true ) {
// the code to enable it ...
}
So I was thinking of changing the way this works (if it would create more efficiency) by doing something like this:
function user__getGlobalConfig( $in_param_name ) {
// DEFINE THE VALUES
$g['user']['enable_username_change'] = true;
$g['user']['enable_image_change'] = true;
$g['user']['display'] = "[LASTNAME], [FIRSTNAME]";
$g['user']['sort_by'] = "[LASTNAME]";
$g['user']['default_locale'] = "english";
$g['user']['profile_page'] = file_get_contents('profile_template.html');
if ( isset( $g['user'][$in_param_name] == true ) {
return $g['user'][$in_param_name];
} else {
return false;
}
}
Then we would access it like this:
if ( user__getGlobalConfig('enable_username_change') == true ) {
// the code to enable it ...
}
So it would seem that the file_get_contents() type values would only get read in when function is called, which I believe would be more efficient, but I may be wrong. The other true/false or simple text based values dont seem that they would be a big efficiency gain, but I pose that here -- any science or fact-based reasoning as to why one way would be more efficient than the other?
Thanks.
If you use the function approach, you should code it so it doesn't recreate the array every time, by using a static variable to cache the settings. In particular, you don't want it to call file_get_contents() every time you look up a setting.
function user__getGlobalConfig( $in_param_name ) {
static $g;
if (!isset($g)) {
$g = array();
// DEFINE THE VALUES
$g['user']['enable_username_change'] = true;
$g['user']['enable_image_change'] = true;
$g['user']['display'] = "[LASTNAME], [FIRSTNAME]";
$g['user']['sort_by'] = "[LASTNAME]";
$g['user']['default_locale'] = "english";
$g['user']['profile_page'] = file_get_contents('profile_template.html');
}
if ( isset( $g['user'][$in_param_name] ) ){
return $g['user'][$in_param_name];
} else {
return false;
}
}
I'm currently working on converting my WIP PHP application to an object oriented architecture, as I've found that for my current project good OOP practices are likely to make it much easier. While refactoring my code a bit I came upon a question that is somewhat elementary, but alas I'm not sure of the answer.
I have a section (aka the 'snippet') of code--the code contained in the "GenerateDBSetObjects()" function of the first code sample--that I feel should be put into a function (ie. somewhat like a subroutine), as outlined in the first sample. I want to put it into a separate function block for two reasons:
Simplify the main code body
Create a function that can be unit tested
However, this creates a problem. Because my program effectively has two large scope variables, so I would need to return two values at once (which is no big deal, as it is a common topic: see this). The question that I have though is: Since I am restructuring my code in an Object-Oriented fashion, might there be a more efficient way to do this? Something maybe that I haven't considered? Or is it just best to simply pass in and return the variables?
Because $NumDBSets and $DBSets[] are basically global scope not really sure what I should do here.
index.php
After
//-------------------------Primary Vars---------------------------------------//
//Fills $ini with a multi-dimensional, associative array that contains all of the
// parameters listed in DBSearchConfig.ini
$ini = (parse_ini_file("config/DBSearchConfig.ini", true))
or die ("Config file: 'DBSearchCongif.ini' could not be read or found in the config folder. Please contact the system administrator");
$LogFile = $ini['SystemVars']['LogFile']; //Assign $LogFile to the location of the system's specific log file found in the .ini
$NumDBSets = 0;//An integer which stores the number of Database sets used by the program.
$DBSets = array(); //Creates an empty array that will store each of the DatabaseSet Objects. Each of the
//Database Sets holds an array of SQL database connection parameters (ie.
//Hostname, Username, etc.), as well as an array of links to the SQL databases within the dataset, et. al.
//For more info see 'DatabaseSet.php'
$CurrDBSetNum = $ini['SystemVars']['DefaultDBSet']; //Get the current DBSet Number from config.
$CurrentConnectionManager = new ConnectionManager;
GenerateDBSetObjects($DBSets, $NumDBSets);
//-------------------------FUNCTIONS----------------------------------------//
function GenerateDBSetObjects(){
//Create, Fill and Assign DatabaseSet Objects. Figure out the number of Database sets.
array_push($DBSets, new DatabaseSet);//Push an empty DatabaseSet object into the list to occupy the '0' index!!!
foreach($ini['Databases'] as $ConnectInfoList){
$NumDBSets ++;
//Create a new DatabaseSet Object for this DB Set!!
$newDBSetObject = new DatabaseSet;
$newDBSetObject->ConnectionInfoList = $ConnectInfoList;
$newDBSetObject->CalculateDBSetFields();
array_push($DBSets, $newDBSetObject);
}
}
VS.
Before
//-------------------------Primary Vars---------------------------------------//
//Fills $ini with a multi-dimensional, associative array that contains all of the
// parameters listed in DBSearchConfig.ini
$ini = (parse_ini_file("config/DBSearchConfig.ini", true))
or die ("Config file: 'DBSearchCongif.ini' could not be read or found in the config folder. Please contact the system administrator");
$LogFile = $ini['SystemVars']['LogFile']; //Assign $LogFile to the location of the system's specific log file found in the .ini
$NumDBSets = 0;//An integer which stores the number of Database sets used by the program.
$DBSets = array(); //Creates an empty array that will store each of the DatabaseSet Objects. Each of the
//Database Sets holds an array of SQL database connection parameters (ie.
//Hostname, Username, etc.), as well as an array of links to the SQL databases within the dataset, et. al.
//For more info see 'DatabaseSet.php'
$CurrDBSetNum = $ini['SystemVars']['DefaultDBSet']; //Get the current DBSet Number from config.
$CurrentConnectionManager = new ConnectionManager;
//Create, Fill and Assign DatabaseSet Objects. Figure out the number of Database sets.
array_push($DBSets, new DatabaseSet);//Push an empty DatabaseSet object into the list to occupy the '0' index!!!
foreach($ini['Databases'] as $ConnectInfoList){
$NumDBSets ++;
//Create a new DatabaseSet Object for this DB Set!!
$newDBSetObject = new DatabaseSet;
$newDBSetObject->ConnectionInfoList = $ConnectInfoList;
$newDBSetObject->CalculateDBSetFields();
array_push($DBSets, $newDBSetObject);
}
If you have decided to take an approach with OOP - consider creating a class which will be responsible for generation and storing DatabaseSet objects.
If object of ConnectionManager class is required for DatabaseSets generation, mark it as dependency injection.
Class DatabaseSet should be declared in separate file: DatabaseSet.php.
Let's call our crucial class DatabaseSetAdapter:
require_once("DatabaseSet.php");
class DatabaseSetAdapter
{
private $config;
private $logFile;
private $NumDBSets = 0;
private $DBSets = [];
private $connManager;
private $currDBSetNum;
public function __construct($iniFilePath, ConnectionManager $manager)
{
$this->config = (parse_ini_file($iniFilePath, true))
or die ("Config file: 'DBSearchCongif.ini' could not be read or found in the config folder. Please contact the system administrator");
$this->logFile = $this->config['SystemVars']['LogFile'];
$this->connManager = $manager;
$this->currDBSetNum = $this->config['SystemVars']['DefaultDBSet'];
}
public function generateDBSetObjects()
{
//Create, Fill and Assign DatabaseSet Objects. Figure out the number of Database sets.
$this->DBSets[] = new DatabaseSet; //Push an empty DatabaseSet object into the list to occupy the '0' index!!!
foreach($this->config['Databases'] as $connectInfoList){
//Create a new DatabaseSet Object for this DB Set!!
$newDBSetObject = new DatabaseSet;
$newDBSetObject->ConnectionInfoList = $connectInfoList;
$newDBSetObject->CalculateDBSetFields();
$this->DBSets[] = $newDBSetObject;
$this->NumDBSets++;
}
}
public function getNumDBSets() // a privileged method
{
return $this->NumDBSets;
}
}
// using of DatabaseSetAdapter:
$dbsetAdapter = new DatabaseSetAdapter("config/DBSearchConfig.ini", new ConnectionManager);
$dbsetAdapter->generateDBSetObjects();
$numDbSets = $dbsetAdapter->getNumDBSets();
....
Global scope and OOP don't fit toghether.
You should have an object keeping this info
class DBSets {
private $num;
private $data;
function __construct() {
$this->num = 0;
$this->data = [];
}
//setters and getters for accessing private properties
}
If $num only stores the count of elements in $data, then you can remove it and use
count($this->data);
got a script which has string variables that represent data fields like they are in the database. because this project is a complete mess this is a stage in cleaning it up and not having to rewrite the field name in numerous locations.
so one script 'DataKeys.php' will have variables set to field names.
//results from query1
$keyField1 = 'field1';
$keyField2 = 'field2';
these two vars above is only a snippet of a much longer list.
I want to access this file and use these vars when I am formatting the data to be more friendly for the front end. this script is being accessed in a class however the fields, $keyField1, defined in the script is not being found in the class. I did have the actual string there but I think single access point would be best so when I make future changes I don't need search the whole project.
class DataFormatter {
//put your code here
public function __construct() {
$documentRoot = filter_input(INPUT_SERVER, "DOCUMENT_ROOT");
include ($documentRoot . '/database/values/DataKeys.php');
}
public function cleanData($data){
if (is_null($data) || empty($data))
{
return;
}
foreach($data as $row){
$field1Value = $row[$keyField1];
unset($row[$keyField1]);
}
}
}
I also tried moving the include outside the class definition.
$documentRoot = filter_input(INPUT_SERVER, "DOCUMENT_ROOT");
include ($documentRoot . '/database/values/DataKeys.php');
The error that is being reported is :
Undefined variable: keyField1
SOULTION
Maybe not the optimal way but I took the include statement and placed it inside the function. The code above is just a demo of what I was trying to achieve not the actual code I am using.
the 2 variables are available just after the "include".
you can for example, put the 2 values in properties of the object
include ...;
$this->keyField1 = $keyField1;
$this->keyField2 = $keyField2;
You have to assign DataKeys.php to class member.
class DataFormatter {
private $keyField1;
private $keyField2;
public function __construct($filename) {
include $filename;
$this->keyField1 = $keyField1;
$this->keyField2 = $keyField2;
}
}
$dataFormatter = new DataFormatter(filter_input(INPUT_SERVER, 'DOCUMENT_ROOT') . '/database/values/DataKeys.php');
i need your help for persist data, i explain :
i have entity Player with variable refer Team :
class DataPlayer
{
/**
* #ORM\ManyToOne(targetEntity="Team")
* #ORM\JoinColumn(name="tag_team", referencedColumnName="tag_team")
*/
private $team;
...
}
but when i include the data, i have only tag of team, not entity team...
because the team is not probably present in database (i include team after).
how can i do to set team with string (the tag directly) whitout to change Entity player
thank!
Okay, I believe I see what you're trying to achieve.
You are doing some sort of import, and during the foreach loop, you're creating Team entities that get associated with your DataPlayer. Obviously you don't want to end up making multiple Teams after the first one has been made with a certain tag, but since you haven't performed a flush() using the Entity Manager yet, you can't findOneByTag() because the Team doesn't yet exist in the database.
This is obviously problematic. So what's the solution? Create a temporary array!
$tempTeams = array();
foreach($teams as $team){
$info = explode(',', str_replace("'", "", $team));
if (isset($tempTeams[$info[1]])) {
$db_team = $tempTeams[$info[1]];
} else {
$db_team = $db->getRepository("ApplicationTestBundle:Team")->findOneByTag($info[1]);
}
if(!$db_team){
$db_team = new Team();
$db_team->setTag($info[1]);
$db_team->setName($info[0]);
$em->persist($db_team);
$tempTeams[$info[1]] = $db_team;
}
$dataT = new DataTeam();
$dataT->setTeam($db_team);
$em->persist($dataT);
$db_team = false; // Need to make sure $db_team is cleared out for the next iteration of the foreach
}
This takes all of your temporary PHP objects before persistence and buffers it into the temporary array, which allows you to recall your new Objects by tag name with no problems. The other solution is to $em->flush(); after $em->persist($db_team);
You can then access the $tempTeams array for later lookups (I believe there was an issue with using $info[4] for the tag this time):
foreach($players as $player){
$info = explode(',', str_replace("'", "", $player));
$db_player = $db->getRepository("ApplicationTestBundle:Player")->findOneByPseudo($info[1]);
$dataJ = new DataPlayer();
$dataJ->setJoueur($db_player);
if (isset($tempTeams[$info[4]])) {
$db_team = $tempTeams[$info[4]];
} else {
$db_team = $db->getRepository("ApplicationTestBundle:Team")->findOneByTag($info[4]);
}
$dataJ->setTeam($db_team);
$em->persist($dataJ);
$db_team = false;
}
I have a function, that check user language and write it down in a variable. After a time, i come of idea to merge they, so that i need a call the function anytime before the first use of a variable, so i put a call of function inside of var, with a idea, that i would be replace it self. But it does not working, becouse it trying to give me a "Closure Object" back, i think it is a function in clear and not the result :( Here is the important part of code:
$GLOBALS['user_language'] = function()
{
return get_user_language();
}
function get_user_language()
{
$user_language = 'en';
$GLOBALS['user_language'] = $user_language;
return $user_language;
}
//somewhere in the script
print_r($GLOBALS['user_language']);
I wish to get 'en' out, nothing more.
function get_user_language()
{
$user_language = 'en';
$GLOBALS['user_language'] = $user_language;
return $user_language;
}
$GLOBALS['user_language'] = get_user_language();
//somewhere in the script
print_r($GLOBALS['user_language']);
But this is strange because you set it already in get_user_language() then you pull it again. It would almost create a loop. The proper way would probably be to remove the $GLOBALS['user_language'] = $user_language; from the function.
Hope this answers your question.
Just use print_r(get_user_language()) instead of print_r($GLOBALS['user_language']);.
If getting the user's language multiple times would be particularly slow (e.g. a database query would be executed over and over again), you can do something like this:
function get_user_language()
{
static $user_language = null;
if ($user_language === null) {
$user_language = 'en'; // this would be where you make the DB query
}
return $user_language;
}
In practice, in a large PHP application, this code would generally be located in a class and would store the value as an object property, so that, for example, the application can cache DB query results for multiple users rather than for only the current one.