Flourish PHP Unframework
This is an archived copy of the forum for reference purposes

buildRecord clauses array does not translate as expected

posted by mblarsen 9 years ago

Hi

I have a problem with building a recordset. The clauses array is not respected 100%. This is the model I worked with (simplified):


CREATE TABLE `shops` (
  `shop_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`shop_id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `products` (
  `product_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `product_code` varchar(255) NOT NULL,
  `catalog` varchar(255) NOT NULL,
  PRIMARY KEY (`product_id`),
  KEY `product_code` (`product_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `product_descriptions` (
  `product_description_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `product_id` int(11) unsigned NOT NULL,
  `shop_id` int(11) unsigned NOT NULL,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`product_description_id`),
  KEY `product_id` (`product_id`),
  KEY `shop_id` (`shop_id`),
  CONSTRAINT `product_descriptions_ibfk_1` FOREIGN KEY (`product_id`) REFERENCES `products` (`product_id`) ON DELETE CASCADE,
  CONSTRAINT `product_descriptions_ibfk_2` FOREIGN KEY (`shop_id`) REFERENCES `shops` (`shop_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `offerings` (
  `offering_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `product_id` int(11) unsigned NOT NULL,
  `shop_id` int(11) unsigned NOT NULL,
  `price` decimal(12,4) unsigned NOT NULL,
  `visibility` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '0 = not visible 1 = catalog and search, 2 = catalog only, 3 = search only',
  PRIMARY KEY (`offering_id`),
  KEY `product_id` (`product_id`),
  KEY `shop_id` (`shop_id`),
  CONSTRAINT `offerings_ibfk_1` FOREIGN KEY (`product_id`) REFERENCES `products` (`product_id`) ON DELETE CASCADE,
  CONSTRAINT `offerings_ibfk_2` FOREIGN KEY (`shop_id`) REFERENCES `shops` (`shop_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

The shop model is irrelevant, included as context.

I'm querying the model with a clauses array like this:

Array
(
    [products=>product_descriptions.shop_id=] => 1
    [shop_id=] => 1
    [visibility=] => 1|2
    [products.product_id=] => 5447|5448|7974
)

This particular query means that I want products for which I have an offering and for which there exists a description. The records I want to retrieve are Offerings.

Invoking this query results in SQL like this:

SELECT offerings.* 
FROM offerings 
LEFT JOIN products ON offerings.product_id = products.product_id 
LEFT JOIN product_descriptions product_descriptions1 ON products.product_id = product_descriptions1.product_id 
WHERE 
	product_descriptions1.shop_id = 1 AND 
	offerings.shop_id = 1 AND 
	offerings.visibility = TRUE AND 
	products.product_id = NULL 
GROUP BY offerings.offering_id, offerings.product_id, offerings.shop_id, offerings.price, offerings.visibility ORDER BY offerings.offering_id ASC

First problem


The clause concerning visibility is translated into a boolean, from:

"visibility=" => "1|2" 

into

visibility = TRUE

where it should have been something like this:

(visibility=1 OR visibility=2)

I suspect this to relate to how booleans are detected in the model. If I convert the value type to smallint instead of tinyint it will translate like this:

visibility = NULL

Second problem


The clause concerning the product ids is translated into NULL. From:

"products.product_id=" => "5447|5448|7974"

into:

products.product_id = NULL

where it should have been something like this:

products.product_id = 5447 OR products.product_id = 5448 OR products.product_id = 7974

I don't have a clue why this happens.

Am I using the clauses notation correctly? (good place to start :)

This is r928 of the lib.

Hi

I figured out so much:

You should use:

"products.product_id=" => array(5447, 5448, 7974)

instead of:

"products.product_id=" => "5447|5448|7974"

(same for the visibility case)

It seems like tinyint is "reserved" for booleans, so as long as I stay away of them everything is working.

Note in fSchema though the data type mapping states:

	'tinyint'	=> 'integer',

I wonder why it interprets it as boolean then?

posted by mblarsen 9 years ago

tinyint(1) isinterpreted as boolean

posted by mungiu 9 years ago

So

tinyint(2)

that is, with length 2, would not be interpreted as boolean?

posted by mblarsen 9 years ago

far is i know, i remember i have this , and that resolve.

posted by mungiu 9 years ago

Yes, one of the downsides of MySQL is how they play fast and loose with the SQL spec. Unfortunately they interpret the BOOLEAN data type as tinyint(1), making it impossible to determine which was intended. Currently Flourish interprets tinyint(1) as a boolean, which tends not to be too big an issue since tinyint(1), tinyint(2), tinyint(3), tinyint(4) and tinyint all use 1 bytes of storage and can store the values -128 to 127. Thus, using any of the variations of tinyint other than tinyint(1) will result in the desired functionality.

If you are using an existing database and the schema can not be changed, there is now an example in the fSchema::getColumnInfo() API docs that shows how to override the detected column information, and treat the column as an integer, even if it uses tinyint(1).

posted by wbond 9 years ago