Need a simple ORM or DBAL for existing PHP app - php

I am working on extending an existing PHP application. Unfortunately for me, the existing app is a mess. It's all spaghetti code with raw mysql_* calls. Groan. No way that I am going to do that in the parts that I am extending.
So, I am looking for a simple ORM of DBAL that I can easily drop in and start using. Desired features:
It must work on an existing database schema. Preferably with minimal or no additional configuration. The existing database schema is the same quality as the existing PHP code (no sensible naming conventions, not normalised, etc.). I don't want to spend days converting the database schema manually into annotated object properties a la Doctrine 2.
It must be able to work alongside the existing raw mysql_* queries. I have no idea how hydrating ORMs like Doctrine 2 or Propel behave when scripts are manually manipulating the data in the database behind their backs, but I assume it's not pretty.
It must run on PHP 5.2.x. I'd love to use PHP 5.3 but I have zero interest in going over the existing 125K lines of spaghetti code mess to make sure it runs on PHP 5.3.
Relationships not required. In the few places I need to get to relational data, I'll be happy to call an extra find() or query() or whatever myself.
Bonus points if it has some trigger support (e.g. beforeSave, afterSave). Not a requirement, but just nice to have.
Edit: Someone put me out of my misery. I just found out that the 125K lines of spaghetti code also changes the database schema. E.g, add an extra option somewhere and a whole slew of ALTER TABLE statements start flying. I could probably fill a year's worth of TheDailyWTF with this codebase. So, one more requirement:
Must be able to cope with a changing database schema automatically (e.g. adding columns).
I have been looking at a few solutions, but I am unsure how well they would work given the requirements. Doctrine 2, RedBeanPhp and the like all require PHP 5.3, so they are out. There's a legacy version of RedBeanPhp for PHP 5.2.x but I don't know if it would work with a messy, existing database schema. NotORM looks okay for getting data out but I don't know if it can be configured for the existing database schema, and how you can easily put data back into the database.
Ideally I would like something simple. E.g:
$user = User::find($id);
$user->name = 'John Woo';
$user->save();
Or:
$articles = ORM::find('article')->where('date' => '2010-01-01');
foreach ($articles as $article) {
echo $article->name;
}
Any tips or even alternative solutions are welcome!

I use...
http://github.com/j4mie/idiorm/
it has an active record implementation too in the form of Paris.
With regard to your edit. Idiorm copes with changing schemas and the syntax almost exactly matches the type you want in your question.

How well did you look into Doctrine? I am using Doctrine 1.2 for these kind of things. Quite easy to setup, allows you to start off with an existing schema. It automatically figures out the relations between tables that have foreign key constraints.
It has extensive trigger and behaviour support, so the bonus points can be spent as well, and it has relational support as well, so your additional queries are not necessary. It has beautiful lazy loading, and it comes with a flexible query language (called DQL) that allows you to do almost exactly the same stuff that you can do in SQL in only a fraction of the effort.
Your example will look like this:
/* To just find one user */
$user = Doctrine::getTable('User')->findOneById($id);
/* Alternative - illustrating DQL */
$user = Doctrine_Query::create()
->from('User u')
->where('u.id = ?',array($id))
->fetchOne();
$user->name = 'John Woo';
$user->save();
It must be able to work alongside the existing raw mysql_* queries. I have no idea how hydrating ORMs like Doctrine 2 or Propel behave when scripts are manually manipulating the data in the database behind their backs, but I assume it's not pretty.
Well, that is technically impossible to auto-manage; a SQL database is simply not pushing back stuff to your ORM, so to update stuff that was changed in the background, you need to perform an additional query one way or the other. Fortunately, Doctrine makes this very easy for you:
/* #var User $user */
/* Change a user using some raw mysql queries in my spaghetti function */
$this->feedSpaghetti($user->id);
/* Reload changes from database */
$user->refresh();

Related

Modifying the SQL Eloquent uses per connection

I'm using the latest version of Laravel to connect to multiple data sources. One of those sources is an old Oracle database that contains a lot of white space thanks to some ancient software requiring string length. Despite this constraint, the fields have since been edited by new software with different requirements, and the columns are all varying length (and thus unknown).
On account of this, I need to edit the SQL that accesses it in order to wrap some pieces of the queries in trim()s. For instance,
$customer = Customer::whereRaw("RTRIM(\"ID\") = TO_CHAR($id)")->get();
I'd like to be able to merely call the find method:
$customer = Customer::find($id)
This is just one example. Pretty much all of the default functions are broken because the queries need some kind of trim prepended to them. I understand how I can affect the dynamic portion of the query, but I need to edit the column ahead of that. Sorry if this is a dumb question and I've just missed something in the documentation.
The easiest way to do this is to create a class that extends Eloquent, with the function for the query. Then modify all of your models to extend the new class instead of Eloquent. This way the models will have all the functionality of Eloquent as well as the functions you create.

Where to put custom SQL code in CakePHP 3?

I'm building an application in CakePHP 3. It uses a number of legacy databases which are not built in the Cake conventions.
I do not want to use any of the ORM features Cake provides, as it's more tedious to set up all the relations than just write "Raw SQL". We are also not going to make any changes to the database structures, so the ORM is a non-starter. So I'm going to write raw SQL queries for everything.
However, I'm not sure where this code would be put. I've read https://book.cakephp.org/3.0/en/orm/database-basics.html#running-select-statements but it doesn't say where you actually put that code.
I don't want to put my queries in a controller ideally since that defeats the purpose of MVC.
All I really need is one Model where I can put all my queries in different functions and reference them in my Controller(s).
In Cake 2.x it was easy to just create a model under app/Model/ then load it (loadModel) where needed in controller(s). But with the new Cake 3.x Table and Entity spaces, I'm not sure how this fits in?
I've also read up on Modelless Forms but don't think they're right either. For example the initial page of the application shows a list of chemicals which is just a SELECT statement - it doesn't involve forms or user input at all at this stage.
Obviously there will also be situations where I need to pass data from a Controller to the Model, e.g. queries based on user input.
As mentioned in the comments, I would suggest to not ditch the ORM, it has so many benefits, you'll most probably regret it in the long run.
Setting up the tables shouldn't be a big deal, you could bake everything, and do the refactoring with for example an IDE that does the dirty work of renaming references and filenames, and then set up the rules and associations manually, which might be a little tedious, but overally pretty simple, as there shouldn't really be much more to configure with respect to the database schema, than the foreign keys, and possibly the association property names (which might require updating possible entities #property annotations too) - maybe here and there also conditions and stuff, but oh well.
That being said, for the sake of completeness, you can always create any logic you want, anywhere you want. CakePHP is just PHP, so you could simply create a class somewhere in say the Model namespace (which is a natural fit for model related logic), and use it like any other class wherever needed.
// src/Model/SomeModelRelatedClass.php
namespace App\Model;
class SomeModelRelatedClass
{
public function queryTheDatabase()
{
// ...
}
}
$inst = new \App\Model\SomeModelRelatedClass();
$results = $inst->queryTheDatabase();
See also
Cookbook > Database Access & ORM > Associations - Linking Tables Together > BelongsTo Associations

Easiest way to move data to other database

I have two versions of my blog: the 1st is written in PHP and uses MySQL, but the 2nd, the new one, is written in Python and uses Postgres.
My goal is to move data from one to other. Table names and schema changes.
My idea was to make ORM models for old site, and, using loop, get data using ORM and put it in new database, because I have ORM models for my new site too.
It would look something like:
old_articles = OldArticle.objects.all()
for old_article in old_articles:
new_article = NewArticle()
new_article.title = old_article.name
new_article.content = old_article.body
new_article.save()
ORM would easy abstract differences between the databases and, in my opinion, this could actually work! Or no, are there better ways?
If this migration will only be done once, I wouldn't go the ORM way. Exporting standards-compliant SQL dumps from MySQL is possible and the dumps could easily be imported into PostgreSQL. Once the data is in PostgreSQL, run your migration queries to make the scheme changes or use temporary 'import' tables and copy the data to the tables in the new scheme/lay-out.
Test all your migration queries and write a scenario containing all steps to take, which queries to run and in what order. Also include manual steps that need to be performed.
Once you're sure that the migration scenario is correct, and fully tested, put your old blog in 'maintainance mode' (sorry, we're offline, we'll be back soon) and do it for real!
Most important: test your scenario, validate the result and, take your time, you should never hurry these things!
There are a lot of libraries to do this sort of thing. I would stick to something that is already implemented and well tested. Here is a link to the postgres wiki that has a list of tools to do just this thing.
http://wiki.postgresql.org/wiki/Converting_from_other_Databases_to_PostgreSQL

With Doctrine what are the benefits of using DQL over SQL?

Can someone provide me a couple clear (fact supported) reasons to use/learn DQL vs. SQL when needing a custom query while working with Doctrine Classes?
I find that if I cannot use an ORM's built-in relational functionality to achieve something I usually write a custom method in the extended Doctrine or DoctrineTable class. In this method write the needed it in straight SQL (using PDO with proper prepared statements/injection protection, etc...). DQL seems like additional language to learn/debug/maintain that doesn't appear provide enough compelling reasons to use under most common situations. DQL does not seem to be much less complex than SQL for that to warrant use--in fact I doubt you could effectively use DQL without already having solid SQL understanding. Most core SQL syntax ports fairly well across the most common DB's you'll use with PHP.
What am I missing/overlooking? I'm sure there is a reason, but I'd like to hear from people who have intentionally used it significantly and what the gain was over trying to work with plain-ole SQL.
I'm not looking for an argument supporting ORMs, just DQL when needing to do something outside the core 'get-by-relationship' type needs, in a traditional LAMP setup (using mysql, postgres, etc...)
To be honest, I learned SQL using Doctrine1.2 :) I wasn't even aware of foreign-keys, cascade operations, complex functions like group_concat and many, many other things. Indexed search is also very nice and handy thing that simply works out-of-the-box.
DQL is much simpler to write and understand the code. For example, this query:
$query = ..... // some query for Categories
->leftJoin("c.Products p")
It will do left join between Categories and Products and you don't have to write ON p.category_id=c.id.
And if in future you change relation from one-2-many to let's say many-2-many, this same query will work without any changes at all. Doctrine will take care for that. If you would do that using SQL, than all the queries would have to be changed to include that intermediary many-2-many table.
I find DQL more readable and handy. If you configure it correctly, it will be easier to join objects and queries will be easier to write.
Your code will be easy to migrate to any RDBMS.
And most important, DQL is object query language for your object model, not for your relational schema.
Using DQL helps you to deal with Objects.
in case inserting into databae , you will insert an Object
$test = new Test();
$test->attr = 'test';
$test->save();
in case of selecting from databae, you will select an array and then you can fill it in your Object
public function getTestParam($testParam)
{
$q=Doctrine_Query::create()
->select('t.test_id , t.attr')
->from('Test t ')
$p = $q->execute();
return $p;
}
you can check the Doctrine Documentation for more details
Zeljko's answer is pretty spot-on.
Most important reason to go with DQL instead of raw SQL (in my book): Doctrine separates entity from the way it is persisted in database, which means that entities should not have to change as underlying storage changes. That, in turn, means that if you ever wish to make changes on the underlying storage (i.e. renaming columns, altering relationships), you don't have to touch your DQL, because in DQL you use entity properties instead (which only happen to be translated behind the scenes to correct SQL, depending on your current mappings).

using both active record and doctrine in codeigniter

I was curious to know whether its ok if I user codeigniter's active record query besides using doctrine in some cases, simultaneously. Because in some cases, I find active record more easy and quick way to get things done then writing doctrine query. For example, consider the following case where I need to return total number of rows in a table, in doctrine:
$query = $this->em->createQueryBuilder()
->select("count(c)")
->from($this->entity, "c")
->getQuery();
return $query->getSingleScalarResult();
vs via active record:
return $this->db->count_all_results($this->table);
You can see how easy it is in active record. There may be more such cases. So, is there any pros or cons in using both?
Also, will they use two different db connection to perform their operations?
You can use both Doctrine and ActiveRecord at the same time. Swordfish has highlighted the some problems. In addition to that if you bring in new developer team, the learning curve will be more.
I suggest choose one and stick with it. IMO, both are equally good. You should choose based on your current project and personal preference. You can find the very good comparison here
What Does Doctrine Add Above Active Record - CodeIgniter?
Regarding the two queries you mentioned, if you use DQL, it might look simple
$query = $em->createQuery('SELECT COUNT(u.id) FROM Entities\User u');
$count = $query->getSingleScalarResult();
I was curious to know whether its ok if I user codeigniter's active
record query besides using doctrine in some cases, simultaneously
Yes it is ok. There's no rule against it.
Also, will they use two different db connection to perform their
operations?
Depends on how you use them. Connection pooling in PHP is not how it is in other languages. You might have to write a custom class to hook them both up to use a common connection, but its not something that id spend my time for if im in an hurry.
Regarding Pros and Cons
It is good to stick with active record as far as codeigniter is concerned as it is cleaner, efficient and comes as part of codeigniter and provide you almost everything that you might need. You can get the extended active record class from codeigniter forums that extends on the base class to provide some complex join functionality as well.
But technically its not an issue using two layers, other than the fact that it gets messy, and makes two separate connections.
Find the link for the doctrine integration in CI
https://github.com/mitul69/codeigniter-doctrine-integration
I will update more document in couple of days.

Categories