I'm trying to add a reference from the default Spring
Security user domain class to another class which should hold additional
user info.
...and...
From what I read this should be the way it works, but I get the following error :
Any idea?=======================================================================
We need to see your
BootStrap to be sure, but I suspect it's because you're doing something like
and your new User is failing validation (which causes save to return null ).If you use save(failOnError:true) you should get a different exception with a better indication of what the real problem is. Check that you have the right constraints in your User class, in particular note that GORM properties are by default non-nullable so if you want to be able to save a User that doesn't have a Profile you will need to add a constraint of profile(nullable:true) . |
Monday, October 29, 2012
Monday, October 22, 2012
Tutorial Details
- Topic - Database Access in PHP
- Difficulty - Moderate
To put it plainly, if you're still using PHP's old
mysql
API to connect to your databases, read on!What?
It's possible that, at this point, the only thought in your mind is, "What the heck is PDO?" Well, it's one of PHP's three available APIs for connecting to a MySQL database. "Three," you say? Yes; many folks don't know it, but there are three different APIs for connecting:mysql
mysqli
– MySQL Improvedpdo
– PHP Data Objects
mysql
API certainly gets the job done, and has become so popular largely due
to the fact that it makes the process of retrieving some records from a
database as easy as possible. For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| /* * Anti-Pattern */ # Connect mysql_connect( 'localhost' , 'username' , 'password' ) or die ( 'Could not connect: ' . mysql_error()); # Choose a database mysql_select_db( 'someDatabase' ) or die ( 'Could not select database' ); # Perform database query $query = "SELECT * from someTable" ; $result = mysql_query( $query ) or die ( 'Query failed: ' . mysql_error()); # Filter through rows and echo desired information while ( $row = mysql_fetch_object( $result )) { echo $row ->name; } |
- Deprecated: Though it hasn't been officially deprecated – due to widespread use – in terms of best practice and education, it might as well be.
- Escaping: The process of escaping user input is left to the developer – many of which don't understand or know how to sanitize the data.
- Flexibility: The API isn't flexible; the code above is tailor-made for working with a MySQL database. What if you switch?
How?
When I was first learning about the PDO API, I must admit that it was slightly intimidating. This wasn't because the API was overly complicated (it's not) – it's just that the oldmyqsl
API was so dang easy to use!Don't worry, though; follow these simple steps, and you'll be up and running in no time.
Connect
So you already know the legacy way of connecting to a MySQL database:
1
2
| # Connect mysql_connect( 'localhost' , 'username' , 'password' ) or die ( 'Could not connect: ' . mysql_error()); |
1
| $conn = new PDO( 'mysql:host=localhost;dbname=myDatabase' , $username , $password ); |
What's nice about this approach is that, if we instead wish to use a sqlite database, we simply update the DSN, or "Data Source Name," accordingly; we're not dependent upon MySQL in the way that we are when use functions, like
mysql_connect
.Errors
But, what if there's an error, and we can't connect to the database? Well, let's wrap everything within atry/catch
block:
1
2
3
4
5
6
| try { $conn = new PDO( 'mysql:host=localhost;dbname=myDatabase' , $username , $password ); $conn ->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e ) { echo 'ERROR: ' . $e ->getMessage(); } |
PDO::ERRMODE_SILENT
. With this setting left unchanged, you'll need to manually fetch errors, after performing a query.
1
2
| echo $conn ->errorCode(); echo $conn ->errorInfo(); |
PDO::ERRMODE_EXCEPTION
, which will fire exceptions as they occur. This way, any uncaught exceptions will halt the script.For reference, the available options are:
PDO::ERRMODE_SILENT
PDO::ERRMODE_WARNING
PDO::ERRMODE_EXCEPTION
Fetch
At this point, we've created a connection to the database; let's fetch some information from it. There's two core ways to accomplish this task:query
and execute
. We'll review both.Query
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| /* * The Query Method * Anti-Pattern */ $name = 'Joe' ; # user-supplied data try { $conn = new PDO( 'mysql:host=localhost;dbname=myDatabase' , $username , $password ); $conn ->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $data = $conn ->query( 'SELECT * FROM myTable WHERE name = ' . $conn ->quote( $name )); foreach ( $data as $row ) { print_r( $row ); } } catch (PDOException $e ) { echo 'ERROR: ' . $e ->getMessage(); } |
PDO::quote
method. Think of this method as, more or less, the PDO equivalent to use mysql_real_escape_string
;
it will both escape and quote the string that you pass to it. In
situations, when you're binding user-supplied data to a SQL query, it's
strongly advised that you instead use prepared statements. That said, if
your SQL queries are not dependent upon form data, the query
method is a helpful choice, and makes the process of looping through the results as easy as a foreach
statement.Prepared Statements
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| /* * The Prepared Statements Method * Best Practice */ $id = 5; try { $conn = new PDO( 'mysql:host=localhost;dbname=myDatabase' , $username , $password ); $conn ->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt = $conn ->prepare( 'SELECT * FROM myTable WHERE id = :id' ); $stmt ->execute( array ( 'id' => $id )); while ( $row = $stmt ->fetch()) { print_r( $row ); } } catch (PDOException $e ) { echo 'ERROR: ' . $e ->getMessage(); } |
prepare
method to, literally, prepare the query, before the user's data has
been attached. With this technique, SQL injection is virtually
impossible, because the data doesn't ever get inserted into the SQL
query, itself. Notice that, instead, we use named parameters (:id
) to specify placeholders.
Alternatively, you could use ?
parameters, however, it makes for a less-readable experience. Stick with named parameters.
Next, we execute the query, while passing an array, which contains the data that should be bound to those placeholders.
1
| $stmt ->execute( array ( 'id' => $id )); |
bindParam
method, like so:
1
2
| $stmt ->bindParam( ':id' , $id , PDO::PARAM_INT); $stmt ->execute(); |
Specifying the Ouput
After calling theexecute
method, there are a variety of different ways to receive the data: an
array (the default), an object, etc. In the example above, the default
response is used: PDO::FETCH_ASSOC
; this can easily be overridden, though, if necessary:
1
2
3
| while ( $row = $stmt ->fetch(PDO::FETCH_OBJ)) { print_r( $row ); } |
- PDO::FETCH_ASSOC: Returns an array.
- PDO::FETCH_BOTH: Returns an array, indexed by both column-name, and 0-indexed.
- PDO::FETCH_BOUND: Returns TRUE and assigns the values of the columns in your result set to the PHP variables to which they were bound.
- PDO::FETCH_CLASS: Returns a new instance of the specified class.
- PDO::FETCH_OBJ: Returns an anonymous object, with property names that correspond to the columns.
1
2
3
4
5
6
7
8
9
10
11
| $stmt ->execute( array ( 'id' => $id )); # Get array containing all of the result rows $result = $stmt ->fetchAll(); # If one or more rows were returned... if ( count ( $result ) ) { foreach ( $result as $row ) { print_r( $row ); } } else { echo "No rows returned." ; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| $id = 5; try { $conn = new PDO( 'mysql:host=localhost;dbname=someDatabase' , $username , $password ); $stmt = $conn ->prepare( 'SELECT * FROM myTable WHERE id = :id' ); $stmt ->execute( array ( 'id' => $id )); $result = $stmt ->fetchAll(); if ( count ( $result ) ) { foreach ( $result as $row ) { print_r( $row ); } } else { echo "No rows returned." ; } } catch (PDOException $e ) { echo 'ERROR: ' . $e ->getMessage(); } |
Multiple Executions
The PDO extension becomes particularly powerful when executing the same SQL query multiple times, but with different parameters.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| try { $conn = new PDO( 'mysql:host=localhost;dbname=someDatabase' , $username , $password ); $conn ->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); # Prepare the query ONCE $stmt = $conn ->prepare( 'INSERT INTO someTable VALUES(:name)' ); $stmt ->bindParam( ':name' , $name ); # First insertion $name = 'Keith' ; $stmt ->execute(); # Second insertion $name = 'Steven' ; $stmt ->execute(); } catch (PDOException $e ) { echo $e ->getMessage(); } |
CRUD
Now that you have the basic process in place, let’s quickly review the various CRUD tasks. As you’ll find, the required code for each is virtually identical.Create (Insert)
1
2
3
4
5
6
7
8
9
10
11
| try { $pdo = new PDO( 'mysql:host=localhost;dbname=someDatabase' , $username , $password ); $pdo ->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt = $pdo ->prepare( 'INSERT INTO someTable VALUES(:name)' ); $stmt ->execute( array ( ':name' => 'Justin Bieber' )); # Affected Rows? echo $stmt ->rowCount(); // 1 } catch (PDOException $e ) { echo 'Error: ' . $e ->getMessage(); |
Update
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| $id = 5; $name = "Joe the Plumber" ; try { $pdo = new PDO( 'mysql:host=localhost;dbname=someDatabase' , $username , $password ); $pdo ->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt = $pdo ->prepare( 'UPDATE someTable SET name = :name WHERE id = :id' ); $stmt ->execute( array ( ':id' => $id , ':name' => $name )); echo $stmt ->rowCount(); // 1 } catch (PDOException $e ) { echo 'Error: ' . $e ->getMessage(); } |
Delete
1
2
3
4
5
6
7
8
9
10
11
| $id = 5; // From a form or something similar try { $pdo = new PDO( 'mysql:host=localhost;dbname=someDatabase' , $username , $password ); $pdo ->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt = $pdo ->prepare( 'DELETE FROM someTable WHERE id = :id' ); $stmt ->bindParam( ':id' , $id ); // this time, we'll use the bindParam method $stmt ->execute(); echo $stmt ->rowCount(); // 1 } catch (PDOException $e ) { echo 'Error: ' . $e ->getMessage(); } |
Object Mapping
One of the neatest aspects of PDO (mysqli, as well) is that it gives us the ability to map the query results to a class instance, or object. Here’s an example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| class User { public $first_name ; public $last_name ; public function full_name() { return $this ->first_name . ' ' . $this ->last_name; } } try { $pdo = new PDO( 'mysql:host=localhost;dbname=someDatabase' , $username , $password ); $pdo ->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $result = $pdo ->query( 'SELECT * FROM someTable' ); # Map results to object $result ->setFetchMode(PDO::FETCH_CLASS, 'User' ); while ( $user = $result ->fetch()) { # Call our custom full_name method echo $user ->full_name(); } } catch (PDOException $e ) { echo 'Error: ' . $e ->getMessage(); } |
Closing Thoughts
Bottom line: if you’re still using that oldmysql
API for connecting to your databases, stop. Though it hasn’t yet been deprecated, in terms of education and documentation, it might as well be. Your code will be significantly more secure and streamlined if you adopt the PDO extension.An Introduction to MySQL 5: Views
Introduction: What is a View
“A View is nothing more than a pseudo table doing the work of a defined query.”In short, the easiest way to look at a view is that it is just a stored query which mimics a table. It’s nothing more than a pseudo table doing the work of a defined query. It doesn’t add any functionality, such as changing variables, nor does it fire other queries when something else happens. Views just sit there, fat dumb and happy doing what you defined them to do.
On first blush, this doesn’t sound like that big of a deal, but if you dig past the surface, you can start seeing some of the power of the lowly view. I am not going to say that views will change your life, but I will tell you that they will make the job of database interaction a little easier to work with. They will make your job a little easier when you make major version changes in your interaction layer. They will also make some difficult tasks such as dynamic reporting a little more efficient and a little easier to work with. I’ll take a little easier any day of the week.
With anything there are tradeoffs.
“Views may and probably will decrease your performance.”As I have written in the past, I am a believer in making tradeoffs, as long as you understand what is on the table. More than likely someone will skim past this paragraph and make a comment that you should never use a view because of the performance hit. I disagree. You should use every tool in your toolbox, but when they make sense. You don’t use a hammer to put a screw into a wall, just as you wouldn’t use a view when you really need a heap / memory table. The flip side is the development usability for your applications. When it makes sense to save time, effort, and energy over the performance hit that you might take, take that choice. Development isn’t all about the performance of your applications, as there are other considerations such as support, time to market, and overall value of your time.
The tools that I am working with in this tutorial are pretty standard. I am using phpMyAdmin for the database interaction for explanation purposes. I will also be using very rudimentary table structures, strictly for ease of explanation. I don’t expect that these table structures would ever be used in a production environment, as I am merely using them for illustration.
One further note. There is no right or wrong way to name a view. However, I do name my views with the syntax of view_*primary_table*_*what_the_view_is_used_for* unless I am working for backwards compatibility changes. So, if I was creating a view for statistical reporting purposes on my salesforce table, my view name would be: view_salesforce_statistical_report. That can be rather long and you only have 64 characters to work with, so keep that in mind. It works for me, and my style, it might not work for you.
“I am not going to say that views will change your life, but I will tell you that they will make the job of database interaction a little easier to work with. They will make your job a little easier when you make major version changes in your interaction layer. They will also make some difficult tasks such as dynamic reporting a little more efficient and a little easier to work with.”
Definitions: How to Define a View
As I stated, a view is just a query. There are some slight configurations that we need to make when creating a view, so let’s discuss that first. In phpMyAdmin, in the “browse” table page, you will see a link called “Create View”.First, there is “Create View” followed by “OR REPLACE”. If you click the OR REPLACE it will do exactly as you think, which is overwrite an existing view. Column names is the name of the columns in your table. Each is seperated by a comma, so it might look like first_name, second_name, etc. AS is the query.
There are two more items to explain, but the concepts are not hard. ALGORITHM has the selections of undefined, merge, and temp table. If you select “Merge” when there is a one to one relationship it will combine the incoming query with the view. Temp table is less efficient, but when you are not using a one to one relationship, such as a aggregation function like SUM() or you are using certain keywords like GROUP BY or HAVING or UNION, you have to use the temp table algorithm. That said, you can do like I do, and leave the algorithm as “undefined” and MySQL will select the best algorithm to use.
Finally, we have CASCADED CHECK OPTION and LOCAL CHECK options. The check options tell MySQL to validate the view definition if there is a condition on the query, like WHERE. If the WHERE clause excludes data, it will prevent updates or insertion of those rows where it should be excluded. The LOCAL CHECK deals with just the view you are defining, where CASCADED CHECK is for views that you have defined from other views. It will cascade the check for those as well.
That’s a view in a nutshell. Let’s take a look at some use cases to see them in action and where they may help your development efforts.
Backward Compatibility: For the Procrastinator
I have had it happen more times than I would care to mention when I design a single use table which I never think will need to be normalized further inevitably does. Let’s take the example that showed before with a few more records.Instead of going back through our code right now, and instead wait for a normal release cycle, we can create a view to keep our old functionality intact. I changed the name of our sales_force table to sales_force_normalized:
Complex Queries: Making the Hard Bearable
Now that we have our proof of concept under our belts, let’s look at another use. I created another table to capture the sales data from my salesforce table and filled it with some random information. It looks like this:Let’s start by evaluating the total sales, along with some other pertinent information:
Getting this information isn’t that hard. Let’s take this just a step further and use a GROUP BY function and a join function against the salesforce. Again, I am using simplified queries to illustrate. In this case, we want to get the same information that we had from total sales, but this time broken down by our individual sales person.
Conclusion
One other benefit of views is they do provide a further level of security to your applications. You are not exposing your table structure to your application. Instead, you’re exposing something that doesn’t really exist, except as a pseudo table. I wouldn’t call a view a best practice and use them primarily for writing secure applications, but I would look at it as an added benefit.I use views in a limited fashion. Where I use views are as demonstrated above, particularly in the reporting mechanisms in my applications. Writing a query to perform the heavy lifting for me is much easier than writing the logic around more difficult queries. I do take a bit of a hit on my performance from time to time, which I tend to overcome by optimizing the original data structure. I’ve yet to have one be a show stopper in terms of performance, but the day is young. Thanks so much for reading.
Wednesday, October 10, 2012
Tutorial: How to write a WordPress Plugin?
In this tutorial, i will show you how to write a Hello World wordpress plugin, which unlike many believe is surprisingly easy, once you understand the very fundamentals. All you need to have is a basic knowledge of php scripting.
Before we move on coding a plugin, please make sure you remember the following coding practices.
1. Always you chose a unique name to your plugin so that it doesnt collide with names used in other plugins.
2. Make sure you comment wherever and whenever necessary in the code.
3. You will to test the plugin in your localhost (using xampp) along with latest version of wordpress.
Plugin Files & Names
Assigning unique names, documenting and organizing the plugin files is very important part of plugin creation.Although wordpress allows you to place the plugin php file directly into the wp-content/plugins folder, for a good plugin developer you will need to create a folder named hello-world and within place readme.txt and hello-world.php.
The readme.txt contains information about your plugin and can come in handy when you submit your plugin wordpress SVN plugin repository. See the readme sample.
Go ahead and create these files and we will add the content to these files later.
The Plugin Basics
The heart of a wordpress plugins is the below 2 functions (commonly called `hooks`)add_action ($tag, $func) documentation
add_filter ($tag,$func) documentation
It is very important to know the difference between the above functions.
- add_action –> does an action at various points of wordpress execution
- add_filter –> does filtering the data (eg. escaping quotes before mysql insert, or during output to browser.
Plugin Information
Open your hello-world.php and in the first line, add this commented plugin information to your file.Save this php file,
- Place the plugin folder to wordpress > wp-content > plugins,
- Go to your wordpress admin > plugins and you will see the new plugin listed, waiting to get activated.
But this plugin had to do something right?
Why not we make it print “Hello World” when we call it from wordpress theme template files.for that we write the code using add_action below the commented plugin information in the hello-world.php
Thats it! Our Hello World plugin is nearly done and with just few lines of code. When our plugin is activated, add_action command calls our hello_world() function when wordpress starts loading.
Lets Test our Hello World Plugin
We really dont know whether our plugin works or not. To test our plugin, go to plugins, activate the hello-world plugin.Then open your worldpress theme wp-content > themes > default, open any of index.php, archive.php or single.php and place the following code anywhere.
The key here is function_exists() call which checks whether plugin loaded or not and then allows the hook into the plugin function. Call to hello_world() in the theme files without checking it, often leads to “Fatal error: call to undefined function” and our blog would crash, if the hello world plugin is not activated or deleted.
If you carefully notice above graphic, see how the hello world appears. Thats the work of our plugin. It WORKS!
Lets take our plugin one step further!
Why not, we build a plugin options page in admin area and provide a backend for plugin users?Right now, the plugin outputs hello world (its pretty much static) and if somebody wants to output ‘Hello Example’, they need to open the php file and make changes everytime to print different text.
Asking the user to edit plugin files isnt a good idea! As a wordpress plugin developer, it is you, who has to provide a good wordpress options interface in the wp-admin area.
Writing Plugin Options Page
We now create Hello World options page in the wordpress admin area.Here is what we do….
- When plugin gets activated, we create new database field `wp_hello_world_data` using set_options() function.
- When plugin gets deactivated, we delete the database field `wp_hello_world_data`
- We create a options menu for Hello World in WordPress Admin > Settings.
- We save the user entered data in the wordpress database.
- We retrieve the data stored in wordpress database and output it using get_options() function.
Activating/Deactivating Plugin
It is very easy to write a function on what plugin does, when it gets activated. WordPress offers 4 very important functions- register_activation_hook -> Runs on plugin activation
- register_deactivation_hook -> Runs on plugin deactivation
- add_option -> Creates new database field
- get_option -> Retrieves the value in database field.
Similarly when the plugin gets deactivated or removed, we need to clean up things, so we remove the created database field using delete_option.
Plugin Settings Page
This is our final step. All we need to create is plugin settings page in the wordpress admin area. The settings page will update and save the data to the database field `hello_world_data` which we created while activating the plugin. Be sure to checkout creating options page in wordpress codex.Here is a very important thing to remember:The above code, is placed under is_admin() which means it only runs in the wordpress admin area.
The add_action for admin_menu should call a function hello_world_admin_menu() containing add_options_page, which in turn should call a function hello_world_html_code() containing html code. This is how the code should flow! Refer to wordpress administration menus
The below function has the html code for the settings page, containing the form and notice how the php tag is split to accomodate the html code.
and the coding part is..
You must remember 2 things in the above code.Hello World Options
1. Specify the database field we created before in the input text box as `hello_world_data`
value="" />
2. If your form has number of fields (like textbox, selectbox etc), all those should be listed in the value field of page_options, separated by commas. For more information, refer to wordpress documentation
Now, the plugin outputs whatever the user specifies in the hello world settings page.
Thats it! Our plugin is READY!
Dont forget to add documentation to readme.txt.
Enjoy!
Subscribe to:
Posts (Atom)