Welcome, Guest
Username: Password: Remember me

TOPIC: Integrities Constraints, Nullable fields

Integrities Constraints, Nullable fields 30 Nov 2012 05:38 #5692

  • blue-canoe
  • blue-canoe's Avatar
  • Offline
  • Senior Member
  • Posts: 57
  • Thank you received: 16
  • Karma: 7
Hello,

I wanted to share something I ran across and it might help others. In most joomla designs for components etc there are no real strict foreign keys and constraints and the database is usually MyIsam (which does not support this anyway). But there might by situations where it is needed to enforce integrity and set-up a InnoDB database with proper constraints and foreign keys.

In that case, you will need to add the required constraints to the database etc, but you will also need to make some changes to the code. This is from Cook 2.0 a bit easier as there is already a sub class of JTable defined of which all component tables inherited. (In Cook 1.5 you will have to create this yourself).

Anyway, there are two things you will need to add to this sub class. First you need a method which converts foreign keys to null when they are not set (Joomla default is '0'). And the 2nd thing is that you will need to override the 'store' method (to call this new method first) and then call its parent with the parameter 'true', to make sure Joomla will update the field even when it is null.

My version of these two methods are:
/**
     * Method to nullify foreign key fields 
     *
     * @access	protected
     *
     * @return	int	Item id value, 0 if empty
     *
     */
    protected function nullifyEmptyStrings() {
        $conf = & JFactory::getConfig();
        $database = $conf->getValue('config.db');
        $prefix = $conf->getValue('config.dbprefix');
        $fields = $this->getFields();
        $tablename = str_replace('#__', $prefix, $this->getTableName());
        $fields = $this->getFields();

        //print_r($fields);
        foreach (get_object_vars($this) as $fieldName => $fieldValue) {
            if (substr($fieldName, 0, 1) == '_') {
                // ignore internal properties that aren't fields in the table
                continue;
            }

            if (!isset($fields[$fieldName])) {
                // ignore internal properties that aren't fields in the table
                continue;
            }


            $fieldInfo = $fields[$fieldName];

            if ($fieldInfo->Null == 'NO') {
                // ignore fields that don't allow NULL
                continue;
            }

            $query = "SELECT
                                       1
                                    FROM
                                       information_schema.KEY_COLUMN_USAGE
                                    WHERE
                                       TABLE_SCHEMA = '" . $database . "'
                                       AND TABLE_NAME = '" . $tablename . "'
                                       AND REFERENCED_TABLE_NAME IS NOT NULL";

            $this->_db->setQuery($query);
            $fkeys = $this->_db->loadObjectList();
            if ((count($fkeys) > 0) && ($fieldValue == '0')) {
                // set field value to NULL
                $this->$fieldName = NULL;
            }
        }
    }

    /* Override the store method to always update fields, even if null */
    public function store($updateNulls = false) {
        $this->nullifyEmptyStrings();
        return (parent::store(true));
    }

Just to be clear: this is not a Cook issue, but more a Joomla issue (or lack of support for it), but this solution works for me.

Kind regards,

Misha
The administrator has disabled public write access.

Re: Nullable fields 01 Dec 2012 16:08 #5698

  • blue-canoe
  • blue-canoe's Avatar
  • Offline
  • Senior Member
  • Posts: 57
  • Thank you received: 16
  • Karma: 7
Hello,

A little follow-up: I noticed in certain situations the foreign key is set to an empty string my Joomla. So to be safe I have changed one line in the solution above (towards the end):
	if ((count($fkeys) > 0) && (($fieldValue == '0')||($fieldValue == ''))) {
	....
The administrator has disabled public write access.

Re: Nullable fields 02 Dec 2012 11:05 #5716

  • admin
  • admin's Avatar
  • Offline
  • Administrator
  • Chef
  • Posts: 3711
  • Thank you received: 987
  • Karma: 140
Did you tried the Integrity contraints of Cook ?

1. Open the properties of you FK field
2. Define FK Integrity : (reset or cascad)

RESET will reset the fks refering to the deleted item.
CASCAD will delete all items refering to the deleted item.

Cook is proud of this feature. Please use it.

Notice that if an item is deleted with 'CASCAD', it is able to delete again in cascad through unlimited levels !!!!

Exemple : Section > Category > Item
Itegrities on FK_category AND FK_section (I make it simple, you understand...)

So, when you delete a Section, it will delete all the referred Categories AND all the Items reffering to this Category.

Not amazing ?
Coding is now a piece of cake
The administrator has disabled public write access.

Re: Nullable fields 12 Dec 2012 10:38 #6026

  • blue-canoe
  • blue-canoe's Avatar
  • Offline
  • Senior Member
  • Posts: 57
  • Thank you received: 16
  • Karma: 7
Hello,

Yes I looked at those and at times they are very cool. But that is not really what I needed. The issue what I am talking about is to store 'NULL' values in a table for foreign keys instead of the Joomla standard '0'. As mentioned this is only relevant when you have implemented physical foreign key constraints in your database.

Kind regards,

Misha
The administrator has disabled public write access.

Re: Nullable fields 13 Dec 2012 11:13 #6045

  • admin
  • admin's Avatar
  • Offline
  • Administrator
  • Chef
  • Posts: 3711
  • Thank you received: 987
  • Karma: 140
This is true, I am using '0' instead of null, but you can change it manually.
The best way for this is using the database native features as you do. More strong and more fast.

This feature I am proposing is for users that do not implements Inno DB or other libs to do that.

By the way, you can also combine boths. So if your component is installed in a server who do not support theses triggers automations, your component can be able to run as well.

A kind of fallback for integrities when installed on a simple mySql.
If the database does the jobs, your component will only check and find nothing to do. (you keep a good performance - only reading coherency...)
Coding is now a piece of cake
The administrator has disabled public write access.

Re: Nullable fields 19 Jan 2013 10:28 #6478

  • blue-canoe
  • blue-canoe's Avatar
  • Offline
  • Senior Member
  • Posts: 57
  • Thank you received: 16
  • Karma: 7
Hello,

I just realised there was a small bug in my proposed solution. It did not check the column name when checking for foreign keys. The query should be:
            $query = "SELECT
                                       1
                                    FROM
                                       information_schema.KEY_COLUMN_USAGE
                                    WHERE
                                       TABLE_SCHEMA = '" . $database . "'
                                       AND TABLE_NAME = '" . $tablename . "'
                                       AND COLUMN_NAME = '".$fieldName."'
                                       AND REFERENCED_TABLE_NAME IS NOT NULL";
The administrator has disabled public write access.
Time to create page: 0.109 seconds

Get Started