Modifying the SQL Eloquent uses per connection - php

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.

Related

Laravel + MySQL - Storing Eloquent namespaces

I was given this project to work on with absolutely no documentation or contact developer. I noticed in the database dump that they are storing what looks like PHP Namespaces for Eloquent models in a couple tables. For example an address table has a string column named "object_type" with the value always being "App\Entities\Client". I searched through the whole project for the PHP code that would use this value. Hopefully to give me insight to it's purpose. Not to my surprise, the project never uses this value. I just see it hard-coding these values upon insert into the DB.
My question is, is this some sort of Database and/or ORM modeling design practice? If so, could you explain how this could be used in a simple practical sense?
Maybe this was some concept the developer had and it never evolved. It's interesting idea but, the idea of joining through MySQL on a string conditional sounds like torture.
Sounds like Laravel polymorphic relationships:
Custom Polymorphic Types.
By default, Laravel will use the fully qualified class name to store the type of the related model.
And, yes, this is a valid modeling technique, though purists rightly argue this technique abuses normal form.
I am not sure what the developers where thinking.
But imagining we are in a forum with thread and replies to each thread. We maybe want to have a Favourites table where we can save replies and threads.
A way to do it would be to have a column in the favourites table called "object_type" (just to use the same term you have in your case) and then when we save an object into the database with eloquent we can use:
$favourite->object_type = get_class($thread); //or get_class($reply) in case we want a reply
$favourite->save();
This way will save the namespace of that class into the database. But laravel will recognise it when we get it from the database.
Hope this cold be helpful.

Virtual private databases with Eloquent

I want to have variable number databases that appear to be separate but are actually in one MySQL database.
These separate instances should be creatable and destroyable inside the application and while normal users work inside a single database instance, the system administrator could see all of them.
This concept seems similar to Oracle's Virtual Private Databases.
I am willing to implement the functionality in Laravel app but I am not sure how to do it.
I would add column instance_id to tables that I want to be instanced and the plain way would be to include something like where('instance_id', Auth::user()->instance_id) in every query, but this is nightmare to add that to every query...
How can I hide that in a neat way so I could either use something or extend improved model class whenever I need a model to be instanced. I want to do it in a way that I could also query the whole table ignoring instancing if I specify that.

Need a simple ORM or DBAL for existing PHP app

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();

How do I create an empty table with SQL?

This isn't much of an issue with MySQL per-se.
The Full Story
I'm writing a very small PHP framework. It isn't like existing frameworks where they force you to use a certain methodology. It isn't either like a CMS framework. Trust me, I've seen Zend framework and I've used CMSes like Joomla and WordPress extensively, none of them come close to what I'm doing.
Introducing The Issues
I'm writing the Database abstraction part. You get class methods like ::table_exists() etc.
It is designed in a way that people can easily add different database classes and use them instead (eg; mysql, mssql, oracle, flatfile...).
They simply need to write a class which satisfies a base abstract classes'.
The Real Issue
I'm writing the functionality for ::table_create(), but have one main problem: MySQL doesn't like empty tables (ie, without a column).
I have several proposed fixes:
For each new table, create a commonly used column, such as 'id' (type=INT)
For each new table, create a temp column which doesn't use any space as much as possible (perhaps a boolean column?)
Somehow delay table creation until at least one column can be created
This approach is most certainly new, and I'd like to here some unbiased comments about it (anything on the lines of "but no one does it that way" won't do).
Well I would either go with option 1), Adding a generic ID column, which you might find you need anyway, or with option 3) Delaying the table creation. I'm assume after they call ::table_create() they will be calling table_add_col(), etc. So just delay creation until there is at least one column, OR until they actually try and use the table for the first time.
Your proposed fixes look quite good. But I would recommen them in a diffrent order. If you are able to delay the creation, tht's probably the best. My second favorite would be to have a table with only an ID, although you might be delete this column, if you want to create a many-to-many relations table with two foreign keys only.
last of your points.
its really very strange what you are doing here. creating tables on the fly? dynamically or something?
well... whatever you are trying to accomplish. you should have a look at document/object oriented databases like couchdb http://couchdb.apache.org/ ! you can create a document and dynamically add whatever fields you want. those are the closest thing to your "columns"
but as you like it...
your first attempt is ugly because it might lead to conflicts.
the second attempt is clumsy. but if you do so create a col with uniqueprefix_random so you can delete it afterwards.
but its well... i dunno what to say about that.
theird approach seems the only senseful!

How to refactor better model functions in CakePHP?

I'm reading programming best practices and it is said that when creating a function we should make it do a only single specific task.
I got model functions that retrieves data and it's related data. Example:
$this->Student->StudentAssignments();
Currently this function retrieves the student's assignments plus the question for each assignment and data about the student. I use them all. My dilemma is if I try to make separate functions that retrieves the related data (student and question datas) it's taxing since I'm producing more calls to the DB.
What would you guys suggest?
Something to keep in mind when doing this sort of refactoring...
I typically will have a Model->getSomethingAndSomethingElse functions in my models.
These functions are public and meant to be called as a substitute for doing complicated (or any) find calls from the Controller.
What I will usually do is then build up a small collection of private functions in the model.
In your case I might have something along the lines of...
Student->getStudentAssigmentsWithQuestions
that then calls some private functions i.e.
Student->getStudent which might call Student->joinStudentAssignment which in turn might call Assignment->joinAssignmentQuestion etc.
The double underscore prefixes have been removed since markdown wants to bold things because of them. If you are using php5 the underscores aren't really important anyways as long as you use the "private" or "proteced" keywords.
Basically I use the public method as a container for a group of very specific query building or association building private functions within the models. This allows me to have an api that has complex data returned, but I build the query or the result set (depending on the type of data, relationships involved or query complexity) from small pieces - that can ideally be purposed and used in more than one public function call.
I think you're doing fine. But you should reconsider renaming your function to
$this->Student->getStudentAssignmentsWithQuestions
Or whatever you think fit. I think one should try to do as few calls to the database as possible (I assume you're performing a join somewhere in there), instead of fetching each set of elements by specific methods. This can lead to the fact that you'll get more methods (and therefore have to write some more tests), but I think this is the right way to do it.
To defend the design argument:
Your method does just one single task; it fetches student's assignments with each assignment's questions.
No, if you're strictly concerned about code refactoring you should break down that blob into simpler functions that perform a single task as you said. Yes, you will hit more your database but considering how easy is to work with caching in cakephp, performance should not be an issue. And if it is, then you shouldn't worry about code refactoring at this point.

Categories