Juergen Posted April 20, 2016 Share Posted April 20, 2016 Hello @ all, I have created a new fieldtype which should be able to store 4 float values. Therefore I have tried to adapt this fieldtype from Soma. http://modules.processwire.com/modules/fieldtype-dimension/ Instead of storing integer values as in Somas fieldtype I want to store float values (fe. 3.5). Here is what it looks like in the admin: Problem: It stores the values only as integer and not as float. This means if I enter fe 2.5 it stores always 2. Here are the 2 files for the fieldtype: 1) FieldtypeProductDate.module <?php /** * ProcessWire ProductData Fieldtype * Field that stores 4 float values for length/weight/minsize/maxsize. * * ProcessWire 2.x * Copyright (C) 2010 by Ryan Cramer * Licensed under GNU/GPL v2, see LICENSE.TXT * * http://www.processwire.com * http://www.ryancramer.com * */ class FieldtypeProductData extends Fieldtype { public static function getModuleInfo() { return array( 'title' => __('ProductData Fieldtype', __FILE__), // Module Title 'summary' => __('Field that stores 4 float values for length, height and needle minsize and needle maxsize.', __FILE__), // Module Summary 'version' => 100, 'author' => 'Juergen', 'installs' => 'InputfieldProductData' ); } /** * Format value for output * */ public function ___formatValue(Page $page, Field $field, $value) { return $value; } /** * * Add mapping to different name for use in page selectors * This enables us to use it like "field.length=100, field.weight<=200, field.needlemax>100" */ public function getMatchQuery($query, $table, $subfield, $operator, $value) { if($subfield == 'length') $subfield = 'data_length'; if($subfield == 'weight') $subfield = 'data_weight'; if($subfield == 'needlemin') $subfield = 'data_needlemin'; if($subfield == 'needlemax') $subfield = 'data_needlemax'; return parent::getMatchQuery($query, $table, $subfield, $operator, $value); } /** * get Inputfield for this fieldtype, set config attributes so they can be used in the inputfield * */ public function getInputfield(Page $page, Field $field) { $dim = $this->modules->get('InputfieldProductData'); return $dim; } /** * there's none compatible * */ public function ___getCompatibleFieldtypes(Field $field) { return null; } /** * blank value is an WireData object ProductData * */ public function getBlankValue(Page $page, Field $field) { return new ProductData(); } /** * Any value will get sanitized before setting it to a page object * and before saving the data * * If value not of instance ProductData return empty instance */ public function sanitizeValue(Page $page, Field $field, $value) { if(!$value instanceof ProductData) $value = $this->getBlankValue($page, $field); // report any changes to the field values if($value->isChanged('length') || $value->isChanged('weight') || $value->isChanged('needlemin') || $value->isChanged('needlemax')) { $page->trackChange($field->name); } return $value; } /** * get values converted when fetched from db * */ public function ___wakeupValue(Page $page, Field $field, $value) { // get blank dim $dim = $this->getBlankValue($page, $field); // populate the dim $dim->length = (float) $value['data_length']; $dim->weight = (float) $value['data_weight']; $dim->needlemin = (float) $value['data_needlemin']; $dim->needlemax = (float) $value['data_needlemax']; return $dim; } /** * return converted from object to array for storing in database * */ public function ___sleepValue(Page $page, Field $field, $value) { // throw error if value is not of the right type if(!$value instanceof ProductData) throw new WireException("Expecting an instance of ProductData"); $sleepValue = array( 'data_length' => (float) $value->length, 'data_weight' => (float) $value->weight, 'data_needlemin' => (float) $value->needlemin, 'data_needlemax' => (float) $value->needlemax ); return $sleepValue; } /** * Get the database schema for this field * * @param Field $field In case it's needed for the schema, but usually should not. * @return array */ public function getDatabaseSchema(Field $field) { $schema = parent::getDatabaseSchema($field); $schema['data_length'] = 'float NOT NULL default 0'; $schema['data_weight'] = 'float NOT NULL default 0'; $schema['data_needlemin'] = 'float NOT NULL default 0'; $schema['data_needlemax'] = 'float NOT NULL default 0'; // key for data will already be added from the parent $schema['keys']['data_weight'] = 'KEY data_weight(data_weight)'; $schema['keys']['data_needlemin'] = 'KEY data_needlemin(data_needlemin)'; $schema['keys']['data_needlemax'] = 'KEY data_volume(data_needlemax)'; return $schema; } /** * Get any inputfields used for configuration of this Fieldtype. * * This is in addition any configuration fields supplied by the parent Inputfield. * * @param Field $field * @return InputfieldWrapper * */ public function ___getConfigInputfields(Field $field) { $inputfields = parent::___getConfigInputfields($field); // nothing yet return $inputfields; } } /** * Helper WireData Class to hold a dimension object * */ class ProductData extends WireData { public function __construct() { $this->set('length', null); $this->set('weight', null); $this->set('needlemin', null); $this->set('needlemax', null); } public function set($key, $value) { if($key == 'length' || $key == 'weight' || $key == 'needlemin' || $key == 'volume') { // if value isn't numeric, don't change the value if already // one set, else set it to 0 and throw an exception so it can be seen on API usage if(!is_float($value) && !is_null($value)) { $value = $this->$key ? $this->$key : 0; throw new WireException("ProductData Object only accepts number values"); } } return parent::set($key, $value); } public function get($key) { return parent::get($key); } } 2) InputfieldProductData.module <?php /** * ProcessWire ProductData Inputfieldtype * ProcessWire 2.x * Copyright (C) 2010 by Ryan Cramer * Licensed under GNU/GPL v2, see LICENSE.TXT * * http://www.processwire.com * http://www.ryancramer.com * */ class InputfieldProductData extends Inputfield { public static function getModuleInfo() { return array( 'title' => __('ProductData Inputfield', __FILE__), // Module Title 'summary' => __('Simple dimension input field.', __FILE__), // Module Summary 'version' => 100, 'author' => 'Juergen', 'requires' => array("FieldtypeProductData") ); } /** * Construct the Inputfield, setting defaults for all properties * */ /** * Per the Module interface, init() is called when the system is ready for API usage * */ public function init() { return parent::init(); } /** * Return the completed output of this Inputfield, ready for insertion in an XHTML form * * @return string * */ public function ___render() { $out = ''; $value = $this->attr('value') ? $this->attr('value') : new ProductData(); $label_length = $this->_("Length"); $label_weight = $this->_("Weight"); $label_needlemin = $this->_("Needlesize min"); $label_needlemax = $this->_("Needlesize max"); $out .= "<div class='dimension_col'>"; $out .= "<label>{$label_length}: <input type='number' min='0' style='width:100px' name='{$this->name}_length' id='Inputfield_{$this->name}_length' value='{$value->length}'/> m</label>"; $out .= "</div>"; $out .= "<div class='dimension_col'>"; $out .= "<label>{$label_weight}: <input type='number' min='0' style='width:100px' name='{$this->name}_weight' id='Inputfield_{$this->name}_weight' value='{$value->weight}'/> g</label>"; $out .= "</div>"; $out .= "<div class='dimension_col'>"; $out .= "<label>{$label_needlemin}: <input type='number' step='0.5' min='0' style='width:100px' name='{$this->name}_needlemin' id='Inputfield_{$this->name}_needlemin' value='{$value->needlemin}'/></label>"; $out .= "</div>"; $out .= "<div class='dimension_col'>"; $out .= "<label>{$label_needlemax}: <input type='number' step='0.5' min='0' style='width:100px' name='{$this->name}_needlemax' id='Inputfield_{$this->name}_needlemax' value='{$value->needlemax}'/></label>"; $out .= "</div>"; return $out; } /** * Process the input from the given WireInputData (usually $input->get or $input->post), load and clean the value for use in this Inputfield. * * @param WireInputData $input * @return $this * */ public function ___processInput(WireInputData $input) { $name = $this->attr('name'); $value = $this->attr('value'); $dim_names = array( 'length' => $name . "_length", 'weight' => $name . "_weight", 'needlemin' => $name . "_needlemin", 'needlemax' => $name . "_needlemax" ); // loop all inputs and set them if changed foreach($dim_names as $key => $name) { if(isset($input->$name)) { if($value->$key != $input->$name) { if(!is_numeric($input->$name) && !empty($input->$name)) { // in case the input isn't numeric show an error $this->error($this->_("Field only accepts number values")); } else { $value->set($key, (float) $input->$name); $this->trackChange('value'); } } } } return $this; } } I have tried to change different parameters but nothing works. Has anyone an idea? Link to comment Share on other sites More sharing options...
LostKobrakai Posted April 20, 2016 Share Posted April 20, 2016 Are you sure those number inputs are correctly parsed to floats? At least the core did at some time suffer from incorrectly parsed values with , as decimal point. Link to comment Share on other sites More sharing options...
Juergen Posted April 20, 2016 Author Share Posted April 20, 2016 The numbers are entered with a dot and not a comma. I have used the arrows on the right side of the inputfield to increase or decrease the number. It seems that the decimal will be rounded. On the other side, if I enter a decimal directly in the sql table I got a blank output in the field at the admin side. So it outputs and stores only integer. Link to comment Share on other sites More sharing options...
LostKobrakai Posted April 20, 2016 Share Posted April 20, 2016 Did you reinstall the module after the changes to the db schema? What does wakeupValue() hold as value coming from the db? Link to comment Share on other sites More sharing options...
Juergen Posted April 20, 2016 Author Share Posted April 20, 2016 Yes I have reinstalled the fieldtype. How can I check the wakeup value -> with tracy debugger? Link to comment Share on other sites More sharing options...
Juergen Posted April 20, 2016 Author Share Posted April 20, 2016 Wake up value shows fe. 3,5 instead of 3.5. I have added a comma number manually in the database for testing purposes in the format 3.5. Strange that wake up value use a comma instead of the dot. Link to comment Share on other sites More sharing options...
Juergen Posted April 20, 2016 Author Share Posted April 20, 2016 Here are some screenshots from the db and from the admin interface. Link to comment Share on other sites More sharing options...
netcarver Posted April 20, 2016 Share Posted April 20, 2016 I think that sforsman's FieldtypeDecimal uses the SQL Decimal type in the DB Schema, and does explicit ',' -> '.' conversion. Have you had a look at his module? Link to comment Share on other sites More sharing options...
Juergen Posted April 20, 2016 Author Share Posted April 20, 2016 Good idea but no effect. Sanitization: public function sanitizeValue(Page $page, Field $field, $value) { $value = str_replace(",",".",$value); if(!$value instanceof ProductData) { $value = $this->getBlankValue($page, $field); } // report any changes to the field values if($value->isChanged('length') || $value->isChanged('weight') || $value->isChanged('needlemin') || $value->isChanged('needlemax')) { $page->trackChange($field->name); } return $value; } DB schema changed to decimal: public function getDatabaseSchema(Field $field) { $schema = parent::getDatabaseSchema($field); $schema['data_length'] = 'DECIMAL(12,1) NOT NULL default 0'; $schema['data_weight'] = 'DECIMAL(12,1) NOT NULL default 0'; $schema['data_needlemin'] = 'DECIMAL(12,1) NOT NULL default 0'; $schema['data_needlemax'] = 'DECIMAL(12,1) NOT NULL default 0'; // key for data will already be added from the parent $schema['keys']['data_weight'] = 'KEY data_weight(data_weight)'; $schema['keys']['data_needlemin'] = 'KEY data_needlemin(data_needlemin)'; $schema['keys']['data_needlemax'] = 'KEY data_volume(data_needlemax)'; return $schema; } Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now