{"id":16356808,"url":"https://github.com/mstenta/fraction","last_synced_at":"2026-02-09T19:09:33.348Z","repository":{"id":147844415,"uuid":"45478303","full_name":"mstenta/fraction","owner":"mstenta","description":"Provides a \"Fraction\" field type, for storing precise decimals.","archived":false,"fork":false,"pushed_at":"2025-01-09T20:24:24.000Z","size":218,"stargazers_count":0,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"2.x","last_synced_at":"2025-03-24T17:51:47.263Z","etag":null,"topics":["drupal","fraction","precision"],"latest_commit_sha":null,"homepage":"https://drupal.org/project/fraction","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mstenta.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-11-03T16:08:44.000Z","updated_at":"2025-01-09T20:23:00.000Z","dependencies_parsed_at":"2024-06-11T20:27:25.926Z","dependency_job_id":"734830b9-9fc9-4526-b0f6-7bcd35d008b8","html_url":"https://github.com/mstenta/fraction","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mstenta%2Ffraction","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mstenta%2Ffraction/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mstenta%2Ffraction/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mstenta%2Ffraction/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mstenta","download_url":"https://codeload.github.com/mstenta/fraction/tar.gz/refs/heads/2.x","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248287690,"owners_count":21078760,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["drupal","fraction","precision"],"created_at":"2024-10-11T01:44:21.317Z","updated_at":"2026-02-09T19:09:23.337Z","avatar_url":"https://github.com/mstenta.png","language":"PHP","readme":"# FRACTION\n\nA Fraction class and field type for Drupal.\n\n## CONTENTS OF THIS FILE\n\n * Introduction\n * Requirements\n * Installation\n * Usage\n * Fraction Class\n * Fraction Field\n * Automatic Precision\n * Database Storage\n * Views Integration\n * Using This Module for Price Storage\n * Maintainers\n\n## INTRODUCTION\n\nThis module provides two things:\n\n 1. A Fraction PHP class for representing and working with fractions.\n 2. A Fraction field with 2 widgets and 3 formatters.\n\nFor a full description of the module, visit the project page:\nhttps://www.drupal.org/project/fraction\n\nTo submit bug reports and feature suggestions, or to track changes:\nhttps://www.drupal.org/project/issues/fraction\n\n## REQUIREMENTS\n\nThis module requires no modules outside of Drupal core.\n\n## INSTALLATION\n\nInstall as you would normally install a contributed Drupal module. Visit:\nhttps://www.drupal.org/docs/8/extending-drupal-8/installing-drupal-8-modules\nfor further information.\n\n## FRACTION CLASS\n\nUsage:\n\n```\n$fraction = new \\Drupal\\fraction\\Fraction(1, 2);\n```\n\nGet the numerator and denominator (as strings):\n\n```\n$numerator = $fraction-\u003egetNumerator();\n$denominator = $fraction-\u003egetDenominator();\n```\n\nConvert the fraction to a decimal with precision 2:\n\n```\n$precision = 2;\n$decimal =  $fraction-\u003etoDecimal($precision);\n```\n\nMultiply fractions:\n\n```\n$fraction1 = new \\Drupal\\fraction\\Fraction(2, 3);\n$fraction2 = new \\Drupal\\fraction\\Fraction(1, 2);\n$fraction1-\u003emultiply($fraction2);\n```\n\nOperations are performed using the BCMath PHP extension, when available.\nOtherwise, normal PHP float operations are used.\n\n## FRACTION FIELD\n\nThe Fraction field allows you to easily add fraction-based decimal storage to\nyour entities using Drupal's Field API.\n\n### Widgets\n\n(for editing the field)\n\n**Fraction** - Two separate text fields for specifying the numerator and\ndenominator separately. This is the best way to store very specific fractions,\nie: 1/3.\n\n**Decimal** - A single textfield that accepts a decimal representation of a\nfraction (ie: 0.33333). This is useful when working with prices. Note that the\ndecimal is converted into a fraction with a base-10 denominator before saving\n(ie: 0.33 becomes 33/100).\n\n### Formatters\n\n(for viewing the field)\n\n**Fraction** - Simply displays the fraction's numerator and denominator\nseparated by a slash, ie: 1/3. The separator can be configured per-field.\n\n**Decimal** - Displays the fraction as a decimal with a fixed precision. For\nexample, the fraction 1/3 can be represented with a precision of 5 as 0.33333.\n\n**Percentage** - Displays the fraction as a percentage with a fixed precision.\nThis works the same as the **Decimal** formatter, but the value is multiplied\nby 100. For example, the fraction 1/3 can be represented with a precision of\n5 as 33.33333%.\n\n## AUTOMATIC PRECISION\n\nFraction can automatically determine the precision of a fraction, as long as the\ndenominator is base 10.\n\nAutomatic precision can be used in the fraction class's toDecimal() method by\nsetting the second parameter to TRUE:\n\n```\n$precision = 2;\n$auto_precision = TRUE;\n$decimal = $fraction-\u003etoDecimal($precision, TRUE);\n```\n\nIn the above example, if the fraction's denominator is not base 10, then the\nprecision defined in the first parameter will be used. If the denominator is\nbase 10, the precision will be automatically calculated.\n\nThe \"Decimal\" widget and formatter both provide an option to enable automatic\nprecision.\n\n## DATABASE STORAGE\n\nFractions are stored in the database using two columns: a numerator and a\ndenominator.\n\nThe numerator is represented as a signed BIGINT, which allows for a range of\nvalues between -9223372036854775808 and 9223372036854775807.\n\nThe denominator is represented as a signed INT, which allows for a range of\nvalues between -2147483648 to +2147483647, but a constraint is added to ensure\nit is always a positive non-zero integer.\n\nFor modules that want to implement their own numerator and denominator columns\nin a database table, the following schema can be used as an example (for use in\nhook_schema()):\n\n```\n/**\n * Implements hook_schema().\n */\nfunction mymodule_schema() {\n  $schema['mymodule_table'] = [\n    'fields' =\u003e [\n\n      ...\n\n      'value_numerator' =\u003e [\n        'description' =\u003e 'Value numerator',\n        'type' =\u003e 'int',\n        'size' =\u003e 'big',\n        'not null' =\u003e FALSE,\n      ],\n      'value_denominator' =\u003e [\n        'description' =\u003e 'Value denominator',\n        'type' =\u003e 'int',\n        'not null' =\u003e FALSE,\n      ],\n\n      ...\n\n    ],\n  ];\n  return $schema;\n}\n```\n\n## VIEWS INTEGRATION\n\nViews integration is provided by Views itself on behalf of the core Field\nmodule. Fraction extends some of the field handlers to allow sorting and\nfiltering by the decimal equivalent of the fraction value (calculated via\nformula in the database query).\n\nFor modules that want to implement their own fraction-based database storage\n(see Database Storage above), Fraction also provides a general-purpose Views\nfield handler that can be used in hook_views_data(). Using the same example\ndescribed in Database Storage above, here is what that would look like:\n\n```\n/**\n * Implements hook_views_data().\n */\nfunction mymodule_views_data() {\n\n  ...\n\n  // Value numerator.\n  $data['mymodule_table']['value_numerator'] = [\n    'title' =\u003e t('Value numerator'),\n    'help' =\u003e t('The stored numerator value.'),\n    'field' =\u003e [\n      'id' =\u003e 'numeric',\n      'click sortable' =\u003e TRUE,\n    ],\n    'filter' =\u003e [\n      'id' =\u003e 'numeric',\n    ],\n    'sort' =\u003e [\n      'id' =\u003e 'standard',\n    ],\n  ];\n\n  // Value denominator.\n  $data['mymodule_table']['value_denominator'] = [\n    'title' =\u003e t('Value denominator'),\n    'help' =\u003e t('The stored denominator value.'),\n    'field' =\u003e [\n      'id' =\u003e 'numeric',\n      'click sortable' =\u003e TRUE,\n    ],\n    'filter' =\u003e [\n      'id' =\u003e 'numeric',\n    ],\n    'sort' =\u003e [\n      'id' =\u003e 'standard',\n    ],\n  ];\n\n  // Create a new decimal column with fraction decimal handlers.\n  $fraction_fields = [\n    'numerator' =\u003e 'value_numerator',\n    'denominator' =\u003e 'value_denominator',\n  ];\n  $data['mymodule_table']['value_decimal'] = [\n    'title' =\u003e t('Value (decimal)'),\n    'help' =\u003e t('Decimal equivalent of the value.'),\n    'real field' =\u003e 'value_numerator',\n    'field' =\u003e [\n      'id' =\u003e 'fraction',\n      'additional fields' =\u003e $fraction_fields,\n      'click sortable' =\u003e TRUE,\n    ],\n    'sort' =\u003e [\n      'id' =\u003e 'fraction',\n      'additional fields' =\u003e $fraction_fields,\n    ],\n    'filter' =\u003e [\n      'id' =\u003e 'fraction',\n      'additional fields' =\u003e $fraction_fields,\n    ]\n  ];\n\n  return $data;\n}\n```\n\n## USING THIS MODULE FOR PRICE STORAGE\n\nThis module aims to solve an outstanding issue with price storage in Drupal.\nStoring prices in the database can be tricky if you don't know what the decimal\nprecision will need to be from the beginning. This is often the case when\nmultiple currencies need to be supported, or when you need extra flexibility\nwith decimal precision.\n\nThe 7.x-1.x branch of [Drupal Commerce](http://drupal.org/project/commerce),\nfor instance, ties precision directly to currency. So if all of your products\nare sold with a two-decimal price, but you want to add one with three decimal\nplaces, you need to add a second (duplicate) currency for just those products.\nThere is an outstanding issue in the Commerce queue that is discussing solutions\n(one of which is to use a Fraction-based approach):\nhttps://www.drupal.org/node/1125706\n\nThe alternative to using a decimal-based storage is to use floats. This brings\nmore issues with precision, due to the way that floating-point numbers are\nrepresented in lower-level system storage. The limitations of float precision\nare outlined on PHP's website:\nhttp://www.php.net/manual/en/language.types.float.php (If you're REALLY\ninterested, here's a great video that explains floating-point rounding errors:\nhttps://www.youtube.com/watch?v=PZRI1IfStY0)\n\nFraction overcomes these issues by storing the value as a fraction, using two\ninteger fields in the database. Decimal representation of this fraction is\nprovided in higher-level functions.\n\nThe best way to use this module for price storage is to utilize the \"Decimal\nfield\" widget to collect the price, and the \"Decimal\" formatter to display it.\nThis approach hides the fact that there are actually two numbers being stored in\nthe database: numerator and denominator. This is achieved through a simple\ndecimal-to-fraction conversion when a decimal value is saved.\n\nWhen a decimal is converted to a fraction, the numerator and denominator are\ncalculated such that the denominator is a power of 10. For example, the decimal\n13.95 becomes 1395/100 in the database.\n\nThis means that for price storage, this module supports up to 9 decimal places\nof precision (because the maximum denominator is 4,294,967,295, meaning the\nhighest possible base-10 number that fits into that is 1,000,000,000).\nUltimately, the maximum numerator depends on the size of the denominator. But,\nusing the maximum precision (of 9 decimal places), the biggest number this can\nstore is 9,223,372,036.854775807.\n\n## MAINTAINERS\n\nCurrent maintainers:\n * Michael Stenta (m.stenta) - https://drupal.org/user/581414\n * Pedro Cambra (pcambra) - https://drupal.org/user/122101\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmstenta%2Ffraction","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmstenta%2Ffraction","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmstenta%2Ffraction/lists"}