Materialdesign: Feedback needed on mdi.php

Created on 18 Apr 2018  路  8Comments  路  Source: Templarian/MaterialDesign

Intro

I've been tapping away at a PHP class for MDI for a while now but, not being a "PHP guy", it could do with someone who's more familiar with it throwing an eye over it and pointing out any problems or any ways the code could be improved. You can find it in the Sandbox's repo for now (jump to line 2499 to skip over the array).

Setup

Edit the values of the defaults array constant to set the following defaults:

  • <hex-string> fill: The default fill colour to use when none is provided. Used only by the utf8(), base64() and file() methods.
  • <string> icon: The name of the icon to default to if an invalid icon name is provided.
  • <integer> size: The default width and height of icons when the size is not provided. Used only by the utf8(), base64() and file() methods.

Usage

I wanted to make it as versatile as possible, to cover all possible use cases so there are 6 ways you can implement it, with the first 5 requiring the inclusion of mdi.php in your site's template/files.

materialdesignicons\icon("name")

Simply returns the path data of the icon.

materialdesignicons\svg("name",options)

Returns the complete SVG markup of the icon for inline use. Has the following, optional parameters:

  • <string> $title : Adds a <title> tag to the returned markup.
  • <hex-string> $fill: Adds a fill attribute to the <svg> tag of the returned markup.
  • <integer> $size: Adds width and height attributes to the <svg> tag of the returned markup.
  • <array> $attributes: An array of key/value pairs used to add additional attributes to the <svg> tag of the returned markup. E.G., ["class"=>"mdi"] would add the class attribute with a value of mdi.

materialdesignicons\path("name",options)

Returns the markup for a <path> tag for inline use. Has the following, optional parameters:

  • <hex-string> $fill: Adds a fill attribute to the tag.
  • <array> $attributes: An array of key/value pairs used to add additional attributes to the tag. E.G., ["class"=>"mdi"] would add the class attribute with a value of mdi.

materialdesignicons\utf8("name",options)

Returns a UFT-8 encoded data-URL of the icon, for use in <img> tags and CSS. Has the following optional parameters, which default to those provided in the defaults array:

  • <hex-string> $fill: Adds a fill attribute to the <svg> tag of the returned string.
  • <integer> $size: Adds width and height attributes to the <svg> tag of the returned string.

materialdesignicons\base64("name",options)

As above but returns a base64-encoded data-URL.

<img src="mdi.php?mdi-icon=icon-name">

Finally, you can also use the file directly as an image URL. It takes the following querystring parameters, with the first being required:

  • mdi-icon: The name of the icon to be used.
  • mdi-fill: The hex colour to use for the fill attribute. Defaults to the value of "fill" in the defaults constant.
  • mdi-size: The integer to use for the height & width attributes. Defaults to the value of "size" in the defaults constant.

Testing

You can see mdi.php in action here by editing or removing the querystring parameters.

All 8 comments

Added a path() method to return a <path> tag.

And a WIP of mdi.php is now available in the Sandbox so you can build your own library for testing.

Finally, here's an example of mdi.php being used in an <img> tag.

vector-square

Thanks for this, that would be awesome!
Here is some general feedback:

  • Constructor: I don't think we should provide a default icon. When the $name argument isn't known, we should throw a InvalidArgumentException instead.
  • Icons list should probably not be hardcoded in the same class - we could use a separate constants file, something like this
  • Methods should be documented
  • Namespaces! :-)
  • Code duplication should be reduced (attr string generation)

We could even provide adapters for rendering engines, such as a twig function for instance ({{ mdi('cloud-download', 'svg') }})

Nice work! I would really need something like this in one of my projects, do you want me to take an attempt on refactoring this?

Thanks for the feedback, @chteuchteu. As I said, I'm not a "PHP guy", so any help you can provide would be greatly appreciated - feel free to submit PRs to the Sandbox for now (@Templarian, is it too soon to set up a dedicated repo for this?).

I've made some changes based on @chteuchteu's feedback; see original comment above for updated usage instructions.

I tried implementing an error on an invalid icon name but it didn't work out; it was throwing a fatal error on me, don't know what I was doing wrong.

The thinking on including the icon list in the same file was to keep the whole thing self-contained. With the addition of the namespace, though, I've been able to move it out of the class.

@PeterShaggyNoble You can host the repo for this. It's not really something I can publish with NPM.

I think you have to publish it to https://packagist.org/ for composer to work. Looks like the org mdi is taken. So might have to use a longer name.

Hey! I know it's been a long time, sorry about that!
I had the need to dump mdi svgs in Twig views recently, and came up with this. It uses a local installation of @mdi/svg, and provides an easy way to customize the returned result:

  • classname, such as fill-muted, fill-danger, ...
  • size (with a 24px default)
  • custom attributes (aria-label="Hello"):
public static function mdi(string $icon, string $class = null, int $size = 24, array $attrs = []): string
{
    if (strpos($icon, 'mdi mdi-') === 0) {
        $icon = str_replace('mdi mdi-', '', $icon);
    }

    $filePath = __DIR__.'/../node_modules/@mdi/svg/svg/'.$icon.'.svg';

    if (!is_file($filePath)) {
        throw new \InvalidArgumentException(sprintf('Unrecognized icon %s.', $icon));
    }

    $svg = file_get_contents($filePath);

    preg_match('/(<path d=".+" \/>)/', $svg, $matches);
    $svg = $matches[1];

    // Add some (clean) attributes
    $attributes = array_merge(
        [
            'viewBox' => '0 0 24 24',
            'xmlns' => 'http://www.w3.org/2000/svg',
            'width' => $size,
            'height' => $size,
            'role' => 'presentation',
        ],
        $attrs
    );

    if ($class !== null) {
        $attributes['class'] = $class;
    }

    $svg = sprintf(
        '<svg %s>%s</svg>',
        implode(' ', array_map(
            function ($val, $key) {
                return $key.'="'.htmlspecialchars($val).'"';
            },
            $attributes,
            array_keys($attributes)
        )),
        $svg
    );

    return $svg;
}

The path to node_modules is currently hardcoded, but it would be easy to make it configurable.

Its usage is quite simple:

echo mdi('phone');

// outputs
// <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" role="presentation"><path d="M6.62,10.79C8.06,..."></path></svg>


echo mdi('fire-truck', 'fill-danger', 100, [
    'aria-label' => 'Firetruck',
]);

// outputs
// <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="100" height="100" role="presentation" aria-label="Firetruck" class="fill-danger"><path d="M17.04,2..."></path></svg>

Of course, it doesn't embed the icons path

  • to make it more flexible
  • to avoid having to release a new version each time a new mdi comes out

I think I'll create a composer package really soon, what do you think?

Note: composer package created and published: https://github.com/chteuchteu/MaterialDesignIcons-PHP

Should we close this issue?

Yeah, this can be closed now that you have a repo up & running for it.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

puytr picture puytr  路  3Comments

xaviergonz picture xaviergonz  路  3Comments

kimdv picture kimdv  路  3Comments

emanf picture emanf  路  3Comments

alvaroc1 picture alvaroc1  路  3Comments