Posts tagged twig
Human Readable bytes (Twig Filter Extension)
0Recently we needed a Twig Filter that takes bytes (as an integer) and translates that to the nearest human readable version of it. For example… if you have 100 bytes, that’s easy, it’s written as in “100 B”. But, what if you have more than 1024 bytes? Then, for example of having 2000 bytes, it is “1.953125 KB” (i.e. the first 1024 bytes is a kilobyte and the remaining 976 bytes is 0.953125 kilobytes).
You can read more here: http://en.wikipedia.org/wiki/Byte
What we actually want to do here is “filter” the bytes and translate that to a human readable, close to the biggest denominator, string that makes it easy for us to see the size of data. For instance, it’s very very difficult to see at a glance how big 1234567890 Bytes are, but if you break it down to the closest 1024 multiple, you note that 1234567890 Bytes = 1.15 GB (rounded).
The easy way for us to solve this was to use a Twig Filter Extension. Our extension is used as below:
|
1 |
{{ 123456789012345 | bytesToHuman }} |
… this will take 123456789012345 and divide it by 1024 until it can go no further, and will then eventually print out 112.283 TB
How do we do this? We take advantage of some math and PHP:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$unit = array(); $unit[0] = 'B'; $unit[1] = 'KB'; $unit[2] = 'MB'; $unit[3] = 'GB'; $unit[4] = 'TB'; $unit[5] = 'PB'; $unit[6] = 'EB'; $unit[7] = 'ZB'; $unit[8] = 'YB'; $bytes = 123456789012345; $precision = 3; echo round($bytes / pow(1024, ($i = floor(log($bytes, 1024)))), $precision) . ' ' . $unit[$i]; |
The above code is common use for doing this calculation so I won’t go into this too much. You can read more on this at http://php.net/manual/en/function.log.php in the comments section.
Putting it into a Twig Extension is pretty easy, there’s mainly 3 steps:
- Create the Twig Extension (anywhere, really, we put it in our “util” bundle in Symfony2)
- Register the extension as a service
- Use it 🙂 – anywhere in your project
To create a Twig Extension in Symfony2 read: http://symfony.com/doc/current/cookbook/templating/twig_extension.html
We went one step further though, in order to make the extension a little more flexible. We used a wildcard. In the section where you register your twig filters you may use wildcards, here’s our getFilters method code:
|
1 2 3 4 5 6 7 |
public function getFilters() { $filters = array(); $filters['bytesTo*'] = new Twig_Filter_Method($this, 'bytes2Filter'); return $filters; } |
The wildcard at the end of ‘bytesTo*’ means we can put just about anything we want there. This means we can have a filter saying, even though this might not resolve to the closest GB, we’d like to force it to resolve to GB and end up with something like 0.005 GB or 4000.123 GB even.
Full source of our Extension Class to see it all work together (with some sanity checks) can be seen below:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
class OurCoolTwigExtension extends \Twig_Extension { protected $unit = array(); public function getFilters() { $filters = array(); $filters['bytesTo*'] = new Twig_Filter_Method($this, 'bytes2Filter'); return $filters; } public function __construct() { $this->unit = array(); $this->unit['B'] = 'Bytes'; // 8 bits $this->unit['KB'] = 'Kilobytes'; // 1024 bytes $this->unit['MB'] = 'Megabytes'; // 1048576 bytes $this->unit['GB'] = 'Gigabytes'; // 1073741824 bytes $this->unit['TB'] = 'Terabytes'; // 1099511627776 bytes $this->unit['PB'] = 'Petabytes'; // 1.12589991e15 bytes $this->unit['EB'] = 'Exabytes'; // 1.1529215e18 bytes $this->unit['ZB'] = 'Zettabytes'; // 1.18059162e21 bytes $this->unit['YB'] = 'Yottabytes'; // 1.20892582e24 bytes } public function bytes2Filter($suffix, $bytes, $precision = 2) { $auto = array('Human', 'Auto'); $unit = array_keys($this->unit); if ($bytes <= 0) { return '0 ' . $unit[0]; } if ($suffix == '') { $suffix = 'Auto'; } if (array_search($suffix, array_merge($auto, $unit)) === false) { throw new \Exception('Sorry, you have to specify a legal Byte value or "Human" for automatic. Legal options are: Human, ' . implode(', ', $unit)); } switch ($suffix) { case '': case 'Human': case 'Auto': return round($bytes / pow(1024, ($i = floor(log($bytes, 1024)))), $precision) . ' ' . $unit[$i]; break; default: { $i = array_search($suffix, $unit); return round($bytes / pow(1024, $i), $precision) . ' ' . $unit[$i]; } break; } } } |
This gives us the following ways of using it:
|
1 2 3 4 5 6 7 8 9 |
{{ 123456789012345 | bytesTo }} {{ 123456789012345 | bytesToHuman }} {{ 123456789012345 | bytesToAuto }} {{ 123456789012345 | bytesToKB }} {{ 123456789012345 | bytesToMB }} {{ 123456789012345 | bytesToGB }} {{ 123456789012345 | bytesToTB }} {{ 123456789012345 | bytesToPB }} {{ 12345678901234567890 | bytesToEB }} (note I used a longer number, otherwise this would've just been 0 EB) |
… yielding the following results:
|
1 2 3 4 5 6 7 8 9 |
112.283 TB 112.283 TB 112.283 TB 120563270519.87 KB 117737568.88 MB 114978.095 GB 112.283 TB 0.11 PB 0.0708 EB (note I used a longer number, otherwise this would've just been 0 EB) |
Hope this is helpful and somebody can use this! n-Joy!