I have some legacy DB with many tables (around 100) the old system is run using php and have so many operation with data used in NLP.
I was a bit curious how thing could be done with Rails. I read that ActiveRecord is no good for legacy systems! but I sow some people used it with no problems, So why some clime that?
Also considering the following php code, with many If & SQL statements, some clime that such case is considered as typical data/database task not OO one, so it's better to stay away from AcriveRecord or any other ORM. Is this true? if not, can it be done easily by Rails's ActiveRecord?
Assuming all variables are submitted from a web form. we have some text to be annotate and we have to see if there're any other users that agree with this user who submitted the form. Then we'll update the agree table.
if ($submitted_id !=""){
$sql = "SELECT * FROM annotation WHERE relation_id = $relation_id";
$result = open_query($sql);
while ($row = mysql_fetch_assoc($result)) {
$user_id = $row["user_id"];
$line = "";
$sql = "SELECT * FROM agree WHERE user_id = $user_id AND user_id_agree = $submitted_id LIMIT 1";
$result = open_query($sql);
$line = mysql_fetch_array($result, MYSQL_ASSOC);
if ( $user_id != $submitted_id ) {
if ( $line == "" ) {
mysql_query ("INSERT INTO agree VALUES ('$user_id' , '$submitted_id', '1', CURRENT_TIMESTAMP)");
} else {
$total = $line["total"];
$new_total = $total+1;
mysql_query ("UPDATE agree SET total = $new_total WHERE user_id = $user_id AND user_id_agree = $submitted_id LIMIT 1");
}
}
}
}
Regards
Well, using legacy database schemas with ActiveRecord makes you lose some of its advantages. For instance, Rails takes a "convention over configuration" approach to many things, and ActiveRecord inherits this. For instance, if you have a model called Product, Rails assumes your table will be called "products". For this reason, you don't have to configure the table name. The same holds through for foreign keys, URL conventions, etc. The more you are willing to make your application work the way Rails works, the easier a time you will have. If your goal going in is not "build an application that does X", but rather "convert this application to Ruby and ActiveRecord", the resulting code will not be as clear or idiomatic.
If you try to write an application in the way that is conventional for the tool you are using, you will likely get clearer, more maintainable code as a result.
As for the code you provided, it's not entirely clear to me what it is supposed to do (since I do not have the context to know what "submitted_it", "user_id_agree", "annotation", and so on mean in your application.
Related
I've been working on a PHP project for about 6 month where I'm using a multitier architecture (Data Access Layer , Business Logic Layer, ...).
One of the page of my website has a really long loading time, so I investigated and I realised it was the function from a BLL file that took a longer time to process.
Here's a example of a function in my DAL (here called DAL_Releve) files :
public static function getReleveByAffectationID($id){
$conn = MgtConnexion::getConnexion();
$sql = "SELECT *"
. "FROM releve "
. "WHERE Affectation_ID = :id "
. "AND Date_Releve >= :date ;";
$req = $conn->prepare($sql);
$req->bindValue(":id", $id);
$req->bindValue(":date", $_SESSION["year"]-1 ."-01-01");
$req->execute();
MgtConnexion::closeConnexion($conn);
return $req;
}
Here's a example of a function in my BLL (here called MgtReleve) files :
public static function getReleveByAffectationID($id){
$req = DAL_Releve::getReleveByAffectationID($id);
$releveArray = array();
while($row = $req->fetch(PDO::FETCH_ASSOC)){
$releveArray[] = new releve($row);
}
return $releveArray;
}
As you can see, I return the PDOStatement object $req from the DAL and then fetch it in the BLL.
My problem is here : In my interface file, I'm looping through a array of Affectation and each of them have Releves (so each Releves have an attribute Affectation_ID), like this:
$lesAff = MgtAffectation::getAllAffectation();
//This doesn't return an array of objects but just an Array of arrays like : $array[<number>]["key"] = value;
foreach ($lesAff as $affect){
$lesReleves = MgtReleve::getReleveByAffectationID($affect["Affectation_ID"]);
foreach ($lesReleves as $rel){
//DO STUFF HERE
}
}
FYI : The page loads in 6.622 seconds with the code above and in 0.014 seconds if I remove everything inside the first foreach (except for html code which is not showed here).
Now I'm starting to question my understanding of the multitiers architecture :
If I decide not to fetch $req in my BLL file but in my interface (to loop only once in my queries results instead of twice), what's the purpose of the BLL then if only to return the PDOStatement object? Is there another way to return the data with more efficiency ?
There are many areas of optimization:
Technological optimization: instead of connecting to the database every time you are running a query, you should connect only once and then use this connection through the entire application. I wrote an article on the common errors of Database wrappers, you may find it interesting to read, and especially the part on the database connection.
Architectural optimization. It seems that you could benefit from lazy loading when instead of selecting database rows one by one you could do it in batches. Check this answer on how to run a PDO query with multiple ids at once. So it will take you to run only 68 queries instead of 1200
Database optimization. Make sure that all queries involved are running fast.
Six years ago I started a new PHP OOP project without having any experience so I just made it up as I went along. Anyway, I noticed that my rather powerful mySQL server sometimes gets bogged down far too easily and was wondering what the best way to limit some db activity, when I came up with this, as an example...
private $q_enghours;
public function gEngHours() {
if ( isset($this->q_enghours) ) {
} else {
$q = "SELECT q_eh FROM " . quQUOTES . " WHERE id = " . $this->id;
if ($r = $this->_dblink->query($q)) {
$row = $r->fetch_row();
$r->free();
$this->q_enghours = $row[0];
}
else {
$this->q_enghours = 0;
}
}
return $this->q_enghours;
}
This seems like it should be effective in greatly reducing the necessary reads to the db. If the object property is populated, no need to access the db. Note that there are almost two dozen classes all with the same db access routines for the "getter". I've only implemented this change in one place and was wondering if there is a "best practice" for this that I may have missed before I re-write all the classes.
I'd say that this question is rather based on wrong premises.
If you want to deal with "easily bogged down" database, then you have to dig up the particular reason, instead of just making guesses. These trifle reads you are so concerned with, in reality won't make any difference. You have to profile your whole application and find the real cause.
If you want to reduce number of reads, then make your object to map certain database record, by reading that record and populating all the properties once, at object creation. Constructors are made for it.
As a side note, you really need a good database wrapper, just to reduce the amount of code you have to write for each database call, so, this code can be written as
public function gEngHours() {
if ( !isset($this->q_enghours) ) {
$this->q_enghours = $this->db->getOne("SELECT q_eh FROM ?n WHERE id = ?", quQUOTES, $this->id);
}
return $this->q_enghours;
}
where getOne() method is doing all the job of running the query, fetching row, getting first result from it and many other thinks like proper error handling and making query safe.
I have recently started using codeigniter and I am a bit stuck as it is all rather new to me.
I use to have a config file with database conection and this on it:
$qset = "select * from re_settings";
$rset = mysql_query($qset) or die(mysql_error());
$aset = mysql_fetch_array($rset);
and this would allow me to pull words from database by simply putting this on the site
<?=$aset['SiteTitle']?>
How can I do this in codeigniter? Do I need to have a controller to do this or is it something much simpler than that.
You'll need to become familiar with the concepts of MCV which is how Codeigniter is built on and your ORM framework.
There's a bunch of helpful resources on http://tutorialcodeigniter.com/ or the official docs http://ellislab.com/codeigniter/user-guide/database/examples.html
as an example
$query = $this->db->query('SELECT name, title, email FROM my_table');
foreach ($query->result_array() as $row)
{
echo $row['title'];
echo $row['name'];
echo $row['email'];
}
I strongly recommend to use Datamapper along with CodeIgniter.
You will be surprised on how it is easy to work with your MySQL database.
Say goodbye to "mysql_fetch_array" 's and such.
Have a look : http://datamapper.wanwizard.eu/pages/getadvanced.html
I have recently begun working on a pre-existing PHP application, and am having a bit of trouble when it comes to exactly what I should to improve this application's scalability. I am from a C#.NET background, so the idea of separation of concerns is not new to me.
First off I want to tell you what exactly I am looking for. Currently this application is fairly well-sized, consisting of about 70 database tables and ~200 pages. For the most part these pages simply do CRUD operations on the database, rarely anything actually programmatically intensive. Almost all of the pages are currently using code akin to this:
$x = db->query("SELECT ID, name FROM table ORDER BY name");
if ($x->num_rows > 0) {
while ($y = $x->fetch_object()) {
foreach ($y as $key => $value)
$$key = $value;
Obviously, this is not great for an application that is as large as the one I am supposed to be working on. Now I, being from a C#.NET background, am used to building small-scale applications, and generally building a small Business Object for each object in my application (almost a 1 to 1 match with my database tables). They follow the form of this:
namespace Application
{
public class Person
{
private int _id = -1;
private string _name = "";
private bool _new = false;
public int ID
{
get{ return _id; }
}
public string Name
{
get { return _name; }
set { _name = value; }
}
public Person(int id)
{
DataSet ds = SqlConn.doQuery("SELECT * FROM PERSON WHERE ID = " + id + ";");
if (ds.Tables[0].Rows.Count > 0)
{
DataRow row = ds.Tables[0].Rows[0];
_id = id;
_name = row["Name"].ToString();
}
else
throw new ArgumentOutOfRangeException("Invalid PERSON ID passed, passed ID was " + id);
}
public Person()
{
_new = true;
}
public void save()
{
if (_new)
{
doQuery(" INSERT INTO PERSON " +
" ([Name]) " +
" VALUES " +
" ('" + Name.Replace("'", "''") + "'); ");
}
else
{
SqlConn.doNonQuery(" UPDATE PERSON " +
" SET " +
" [Name] = '" + _name.Replace("'", "''") + "' WHERE " +
" ID = " + _id);
}
}
In shorter terms, they simply have attributes that mimic the table, properties, a constructor that pulls the information, and a method called save that will commit any changes made to the object.
On to my actual question: first of all, is this a good way of doing things? It has always worked well for me. Second, and more importantly, is this also a good way to do things in PHP? I've noticed already that PHP's loose typing has caused me issues in the way I do things, also no method overloading is entirely new. If this isn't a good practice are there any good examples of how I should adapt this project to 3 tiers? Or, possibly I should not attempt to do this for some reason.
I am sorry for the length of the question, but I have been digging on the internet for a week or so to no avail, all I seem to ever find are syntax standards, not structure standards.
Thanks in advance.
There are several patterns that one can follow. I like to use the MVC pattern myself. MVC is about splitting user interface interaction into three distinct roles. There are other patterns though, but for clarity (end length of the post I will only go into MVC). It doesn't really matter which pattern you wish to follow as long as you use the SOLID principles.
I am from a C#.NET background, so the idea of separation of concerns is not new to me.
That's great. Trying to learn PHP will only be an implementation detail at this point.
Obviously, this is not great for an application that is as large as the one I am supposed to be working on.
Glad that we agree :-)
In an MVC pattern you would have:
Model: which does 'all the work'
View: which takes care of the presentation
Controller: which handles requests
When requesting a page it will be handled by the Controller. If the controller needs to get some work done (e.g. getting a user) it would ask the model to do this. When the controller has all the needed info it will render a view. The view only renders all the info.
That person object you were talking about would be a model in the MVC pattern.
I've noticed already that PHP's loose typing has caused me issues in the way I do things
PHP loose typing is pretty sweet (if you know what you are doing) and at the same time can suck. Remember that you can always do strict comparisons by using three = signs:
if (1 == true) // truthy
if (1 === true) // falsy
also no method overloading is entirely new
PHP indeed doesn't really support method overloading, but it can be mimicked. Consider the following:
function doSomething($var1, $var2 = null)
{
var_dump($var1, $var2);
}
doSomething('yay!', 'woo!'); // will dump yay! and woo!
doSomething('yay!'); // will dump yay! and null
Another way would be to do:
function doSomething()
{
$numargs = func_num_args();
$arg_list = func_get_args();
for ($i = 0; $i < $numargs; $i++) {
echo "Argument $i is: " . $arg_list[$i] . "<br />\n";
}
}
doSomething('now I can add any number of args', array('yay!', 'woo!', false));
Or, possibly I should not attempt to do this for some reason.
Of course you should attempt it. When you already have programming experience it shouldn't be too hard.
If you have any more questions you can can find me idling in the PHP chat tomorrow (I'm really need to get some sleep now :-) ).
is this a good way of doing things?
There is no ideal way; there is good and bad for determined situation.
About typing, PHP doesn't loose it; we call that dynamic typing.
About the architecture, when we develop enterprise level web applications, from medium to large scale, we tend to talk about performance on a daily basis.
A good point to start would be reading about some of the most known PHP frameworks, like:
Zend
Symfony
Kohana
From that you can start thinking about architecture.
i am trying to set a tax rate for a guest (not logged in) based on a coupon code.
i have tried every singleton i can think of and am having trouble even manually setting the customertaxrateid that i would like to set.
any ideas?
so update and answer... i made a really stupid mistake placing my code but after finding a complete lack of information about these subjects on the web... i thought i would share some code... commented instead of the custom solution i am using... but it works!!!
the code needs to be added in:
/app/code/core/Mage/Tax/Model/Calculation.php
$couponCode = Mage::getSingleton('checkout/cart')->getQuote()->getCouponCode();
if (!empty($couponCode)) {
$db = Mage::getSingleton('core/resource')->getConnection('core_read');
$query = ""//put your sql query here since magento makes it hard to respect MVC when a group of setters and getters think you are running mysql4 even though you are using mysql5
$result = $db->query($query);
while ($row = $result->fetch() ) {
//lazy method to avoid the need for more error handling
$customerTaxClass = $row['class_id'];
}
}
it should be done in the getRateRequest function before it creates the $request to return.