9

I'm wondering if there's a built in way to output readable file sizes with the Twig templating system. Say I have something like this in my template:

<p>This limit is currently set to {{ maxBytes }}</p>

How could I format maxBytes to display something like 30 GB?

James Dawson
  • 5,309
  • 20
  • 72
  • 126
  • 1
    To my knowledge there is no defined function/filter to do this. Your only solution is to [extend twig](http://twig.sensiolabs.org/doc/advanced.html). – cheesemacfly Mar 07 '13 at 20:50

3 Answers3

28

There are a couple of ways you can go about accomplishing that:

1) get a Twig extension that will handle it for you. One like this one: https://github.com/BrazilianFriendsOfSymfony/BFOSTwigExtensionsBundle

Once enabled you would just do:

{{ maxBytes|bfos_format_bytes }}

And this will give you what you want.

2) You can create a macro that will do this if you dont want to add an entire extension. That would look something like this:

{% macro bytesToSize(bytes) %}
{% spaceless %}
    {% set kilobyte = 1024 %}
    {% set megabyte = kilobyte * 1024 %}
    {% set gigabyte = megabyte * 1024 %}
    {% set terabyte = gigabyte * 1024 %}

    {% if bytes < kilobyte %}
        {{ bytes ~ ' B' }}
    {% elseif bytes < megabyte %}
        {{ (bytes / kilobyte)|number_format(2, '.') ~ ' KiB' }}
    {% elseif bytes < gigabyte %}
        {{ (bytes / megabyte)|number_format(2, '.') ~ ' MiB' }}
    {% elseif bytes < terabyte %}
        {{ (bytes / gigabyte)|number_format(2, '.') ~ ' GiB' }}
    {% else %}
        {{ (bytes / terabyte)|number_format(2, '.') ~ ' TiB' }}
    {% endif %}
{% endspaceless %}
{% endmacro %}

You can read more about where to put and how to use the macros here: http://twig.sensiolabs.org/doc/tags/macro.html

Benoit Duffez
  • 11,839
  • 12
  • 77
  • 125
Chase
  • 9,289
  • 5
  • 51
  • 77
17

Or, just create the twig extension:

ByteConversionTwigExtension.php

<?php
// src/AppBundle/Twig/Extension

namespace AppBundle\Twig\Extension;


class ByteConversionTwigExtension extends \Twig_Extension
{


    /**
     * Gets filters
     *
     * @return array
     */
    public function getFilters()
    {
        return array(
             new \Twig_SimpleFilter('format_bytes', array($this, 'formatBytes')),
        );
    }    

    public function getName()
    {
        return 'format_bytes';
    }

    function formatBytes($bytes, $precision = 2)
    {
        $units = array('B', 'KiB', 'MiB', 'GiB', 'TiB');
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);

        // Uncomment one of the following alternatives
         $bytes /= pow(1024, $pow);

        return round($bytes, $precision) . ' ' . $units[$pow];
    }

}

services.yml

parameters:
    app.byte_conversion_twig_extension.twig.extension.class: AppBundle\Twig\Extension\ByteConversionTwigExtension

services:
    app.byte_conversion.twig.extension:
        class: %app.byte_conversion_twig_extension.twig.extension.class%
        tags:
            - { name: twig.extension }  

Twig template:

{{ variable | format_bytes }}
Benoit Duffez
  • 11,839
  • 12
  • 77
  • 125
devilcius
  • 1,764
  • 14
  • 18
  • 1
    To read as OS does use 1000 (KiB MiB GiB TiB) instead of 1024 – Cassiano Jun 30 '16 at 16:50
  • 1
    Be aware that KiB refers to KibiByte 1 KiB = 1024 B and KB refers to KiloByte as 1KB = 1000 Bytes. Kilo always stands for "times thousand" in international system unit. On the other hand, many software developers (even in well knonw OS) mix all theses units without any regard of the accepted definition. – Sylvain Martin Saint Léon Sep 06 '17 at 13:23
  • Don't want to sound pedantic, but KB has no significance in the international system unit (or, Kelvin Bytes?). It should either be kB or KiB. – Benoit Duffez Jul 02 '19 at 04:46
2

A twig extension for human readable code using symfony 4 coding format and Jeffrey Sambells formatting function:

src/Twig/AppExtension.php

<?php

namespace App\Twig;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;

class AppExtension extends AbstractExtension
{
    /**
     * @var ContainerInterface
     */
    protected $container;


    /**
     * Constructor
     *
     * @param ContainerInterface $container
     */
    public function __construct(
        ContainerInterface $container
    )
    {
        $this->container = $container;
    }

    public function getFilters()
    {
        return array(
            new TwigFilter('formatBytes', array($this, 'formatBytes')),
        );
    }

    /**
     * @param $bytes
     * @param int $precision
     * @return string
     */
    public function formatBytes($bytes, $precision = 2)
    {
        $size = ['B','kB','MB','GB','TB','PB','EB','ZB','YB'];
        $factor = floor((strlen($bytes) - 1) / 3);
        return sprintf("%.{$precision}f", $bytes / pow(1024, $factor)) . @$size[$factor];
    }

}

services.yaml:

App\Twig\AppExtension:
    arguments:
        - '@service_container'
    tags:
        - { name: twig.extension}

usage in template:

{{ bytes| formatBytes }}
{{ bytes| formatBytes(0) }}
Sebastian Viereck
  • 5,455
  • 53
  • 53