<commit_before><?php
namespace Laranix\Themer\Image;

use Laranix\Support\Exception\NotImplementedException;
use Laranix\Themer\FileSettings;
use Laranix\Themer\Theme;
use Laranix\Themer\ThemerFile;

class Image extends ThemerFile
{
    /**
     * Display an image
     *
     * @param string $image
     * @param array  $params
     * @param bool   $default
     * @return null|string
     */
    public function display(string $image, array $params = [], bool $default = false) : ?string
    {
        $cacheKey = $this->cacheKey($image, $params, $default);

        if ($this->files->has($cacheKey)) {
            return $this->files->get($cacheKey);
        }

        $theme = $default ? $this->getDefaultTheme() : $this->getTheme();

        if (!$this->exists($image, $theme)) {
            if (!$default && $this->themeIsDefault($theme)) {
                return $this->display($image, $params, true);
            }

            $this->missing($image, $theme);

            return null;
        }

        $params = array_merge([
            'alt'   => $image,
        ], $params);

        $img = '<img src="' . $this->getWebUrl($image, $theme) . '" ';

        foreach ($params as $key => $param) {
            $img .= $key . '="' . $param . '" ';
        }

        $img .= '/>';

        return $this->files[$cacheKey] = $img;
    }

    /**
     * Display alias
     *
     * @param string $image
     * @param array  $params
     * @param bool   $default
     * @return null|string
     */
    public function show(string $image, array $params = [], bool $default = false) : ?string
    {
        return $this->display($image, $params, $default);
    }

    /**
     * Cached image key
     *
     * @param string $image
     * @param array  $params
     * @param bool   $default
     * @return string
     */
    protected function cacheKey(string $image, array $params = [], bool $default = false) : string
    {
        return hash('crc32', json_encode([$image, $params, $default]));
    }

    /**
     * Add and track a new file
     *
     * @param \Laranix\Themer\FileSettings $settings
     * @throws \Laranix\Support\Exception\NotImplementedException
     */
    public function add(?FileSettings $settings = null)
    {
        throw new NotImplementedException('Method not required for ' . get_class($this));
    }

    /**
     * Render the view
     *
     * @param array|null  $options
     * @param string|null $view
     * @return null|string
     * @throws \Laranix\Support\Exception\NotImplementedException
     */
    public function render(?array $options = [], string $view = null) : ?string
    {
        throw new NotImplementedException('Method not required for ' . get_class($this));
    }

    /**
     * Get repository key for remote files
     *
     * @param \Laranix\Themer\FileSettings $settings
     * @return string
     * @throws \Laranix\Support\Exception\NotImplementedException
     */
    protected function getRemoteRepositoryKey(FileSettings $settings): string
    {
        throw new NotImplementedException('Method not required for ' . get_class($this));
    }

    /**
     * Get repository key for local files
     *
     * @param \Laranix\Themer\FileSettings $settings
     * @return string
     * @throws \Laranix\Support\Exception\NotImplementedException
     */
    protected function getLocalRepositoryKey(FileSettings $settings): string
    {
        throw new NotImplementedException('Method not required for ' . get_class($this));
    }

    /**
     * Get repository key for remote files
     *
     * @param \Laranix\Themer\FileSettings $settings
     * @return string
     * @throws \Laranix\Support\Exception\NotImplementedException
     */
    protected function getCompiledLocalRepositoryKey(FileSettings $settings): string
    {
        throw new NotImplementedException('Method not required for ' . get_class($this));
    }

    /**
     * Process files
     *
     * @param array $options
     * @return array|null
     * @throws \Laranix\Support\Exception\NotImplementedException
     */
    protected function getFilePayload(array $options = []): ?array
    {
        throw new NotImplementedException('Method not required for ' . get_class($this));
    }

    /**
     * Group files together by type
     *
     * @param array $files
     * @return array|null
     * @throws \Laranix\Support\Exception\NotImplementedException
     */
    protected function parseFiles(?array $files): ?array
    {
        throw new NotImplementedException('Method not required for ' . get_class($this));
    }

    /**
     * Create and return settings for file.
     *
     * @param \Laranix\Themer\Theme $theme
     * @param string                $type
     * @param string                $file
     * @return \Laranix\Themer\FileSettings
     * @throws \Laranix\Support\Exception\NotImplementedException
     */
    protected function createFileSettings(Theme $theme, string $type, string $file): FileSettings
    {
        throw new NotImplementedException('Method not required for ' . get_class($this));
    }

    /**
     * Set the subdirectory in the theme for the file type
     *
     * @return string
     */
    protected function getDirectory(): string
    {
        return 'images';
    }

    /**
     * Set config key in themer config
     *
     * @return string
     */
    protected function getConfigKey(): string
    {
        return 'image';
    }

    /**
     * Set settings class name
     *
     * @return string|null
     */
    protected function getSettingsClass(): ?string
    {
        return null;
    }
}
<commit_msg>Update cache handling and HTML string creation<commit_after><?php
namespace Laranix\Themer\Image;

use Laranix\Support\Exception\NotImplementedException;
use Laranix\Themer\FileSettings;
use Laranix\Themer\Theme;
use Laranix\Themer\ThemerFile;

class Image extends ThemerFile
{
    /**
     * Display an image
     *
     * @param string $image
     * @param array  $params
     * @param bool   $default
     * @return null|string
     */
    public function display(string $image, array $params = [], bool $default = false) : ?string
    {
        $cacheKey = $this->cacheKey($image, $params, $default);

        if ($this->hasCachedImage($cacheKey)) {
            return $this->getCachedImage($cacheKey);
        }

        $theme = $default ? $this->getDefaultTheme() : $this->getTheme();

        if (!$this->exists($image, $theme)) {
            if (!$default && $this->themeIsDefault($theme)) {
                return $this->display($image, $params, true);
            }

            $this->missing($image, $theme);

            return null;
        }

        return $this->cacheImage($cacheKey, $this->createHtmlImageString($image, $theme, array_merge([
            'alt'   => $image,
        ], $params)));
    }

    /**
     * Display alias
     *
     * @param string $image
     * @param array  $params
     * @param bool   $default
     * @return null|string
     */
    public function show(string $image, array $params = [], bool $default = false) : ?string
    {
        return $this->display($image, $params, $default);
    }

    /**
     * Create HTML image string
     *
     * @param string                $image
     * @param \Laranix\Themer\Theme $theme
     * @param array                 $params
     * @return string
     */
    protected function createHtmlImageString(string $image, Theme $theme, array $params = [])
    {
        if (!empty($params)) {
            $extra = [];

            foreach ($params as $key => $param) {
                $extra[] = $key . '="' . $param . '"';
            }

            $properties = implode(' ', $extra) . ' ';
        }

        return sprintf('<img src="%s" %s/>', $this->getWebUrl($image, $theme), $properties ?? '');
    }

     /**
     * Check for cached image
     *
     * @param string $key
     * @return bool
     */
    protected function hasCachedImage(string $key) : bool
    {
        return $this->files->has($key);
    }

    /**
     * Get cached image
     *
     * @param string $key
     * @return string
     */
    protected function getCachedImage(string $key) : string
    {
        return $this->files->get($key);
    }

    /**
     * Store image in the cache
     *
     * @param string $key
     * @param string $image
     * @return string
     */
    protected function cacheImage($key, string $image) : string
    {
        $this->files->add($key, $image);

        return $image;
    }

    /**
     * Cached image key
     *
     * @param string $image
     * @param array  $params
     * @param bool   $default
     * @return string
     */
    protected function cacheKey(string $image, array $params = [], bool $default = false) : string
    {
        return hash('crc32', json_encode([$image, $params, $default]));
    }

    /**
     * Add and track a new file
     *
     * @param \Laranix\Themer\FileSettings $settings
     * @throws \Laranix\Support\Exception\NotImplementedException
     */
    public function add($settings)
    {
        throw new NotImplementedException('Method not required for ' . get_class($this));
    }

    /**
     * Render the view
     *
     * @param array|null  $options
     * @param string|null $view
     * @return null|string
     * @throws \Laranix\Support\Exception\NotImplementedException
     */
    public function render(?array $options = [], string $view = null) : ?string
    {
        throw new NotImplementedException('Method not required for ' . get_class($this));
    }

    /**
     * Get repository key for remote files
     *
     * @param \Laranix\Themer\FileSettings $settings
     * @return string
     * @throws \Laranix\Support\Exception\NotImplementedException
     */
    protected function getRemoteRepositoryKey(FileSettings $settings): string
    {
        throw new NotImplementedException('Method not required for ' . get_class($this));
    }

    /**
     * Get repository key for local files
     *
     * @param \Laranix\Themer\FileSettings $settings
     * @return string
     * @throws \Laranix\Support\Exception\NotImplementedException
     */
    protected function getLocalRepositoryKey(FileSettings $settings): string
    {
        throw new NotImplementedException('Method not required for ' . get_class($this));
    }

    /**
     * Get repository key for remote files
     *
     * @param \Laranix\Themer\FileSettings $settings
     * @return string
     * @throws \Laranix\Support\Exception\NotImplementedException
     */
    protected function getCompiledLocalRepositoryKey(FileSettings $settings): string
    {
        throw new NotImplementedException('Method not required for ' . get_class($this));
    }

    /**
     * Process files
     *
     * @param array $options
     * @return array|null
     * @throws \Laranix\Support\Exception\NotImplementedException
     */
    protected function getFilePayload(array $options = []): ?array
    {
        throw new NotImplementedException('Method not required for ' . get_class($this));
    }

    /**
     * Group files together by type
     *
     * @param array $files
     * @return array|null
     * @throws \Laranix\Support\Exception\NotImplementedException
     */
    protected function parseFiles(?array $files): ?array
    {
        throw new NotImplementedException('Method not required for ' . get_class($this));
    }

    /**
     * Create and return settings for file.
     *
     * @param \Laranix\Themer\Theme $theme
     * @param string                $type
     * @param string                $file
     * @return \Laranix\Themer\FileSettings
     * @throws \Laranix\Support\Exception\NotImplementedException
     */
    protected function createFileSettings(Theme $theme, string $type, string $file): FileSettings
    {
        throw new NotImplementedException('Method not required for ' . get_class($this));
    }

    /**
     * Set the subdirectory in the theme for the file type
     *
     * @return string
     */
    protected function getDirectory(): string
    {
        return 'images';
    }

    /**
     * Set config key in themer config
     *
     * @return string
     */
    protected function getConfigKey(): string
    {
        return 'image';
    }

    /**
     * Set settings class name
     *
     * @return string|null
     */
    protected function getSettingsClass(): ?string
    {
        return null;
    }
}

{'fraction_non_alphanumeric': 0.1228550712962217, 'fraction_numerical': 0.0003222428099573028, 'mean_word_length': 2.2102404965089217, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 42, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '634105', 'n_tokens_mistral': 3534, 'n_tokens_neox': 3477, 'n_words': 874}