brainworxx/kreXX

View on GitHub
src/Analyse/Routing/Process/ProcessString.php

Summary

Maintainability
A
0 mins
Test Coverage
A
97%
<?php

/**
 * kreXX: Krumo eXXtended
 *
 * kreXX is a debugging tool, which displays structured information
 * about any PHP object. It is a nice replacement for print_r() or var_dump()
 * which are used by a lot of PHP developers.
 *
 * kreXX is a fork of Krumo, which was originally written by:
 * Kaloyan K. Tsvetkov <kaloyan@kaloyan.info>
 *
 * @author
 *   brainworXX GmbH <info@brainworxx.de>
 *
 * @license
 *   http://opensource.org/licenses/LGPL-2.1
 *
 *   GNU Lesser General Public License Version 2.1
 *
 *   kreXX Copyright (C) 2014-2024 Brainworxx GmbH
 *
 *   This library is free software; you can redistribute it and/or modify it
 *   under the terms of the GNU Lesser General Public License as published by
 *   the Free Software Foundation; either version 2.1 of the License, or (at
 *   your option) any later version.
 *   This library is distributed in the hope that it will be useful, but WITHOUT
 *   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 *   FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 *   for more details.
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this library; if not, write to the Free Software Foundation,
 *   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

declare(strict_types=1);

namespace Brainworxx\Krexx\Analyse\Routing\Process;

use Brainworxx\Krexx\Analyse\Callback\CallbackConstInterface;
use Brainworxx\Krexx\Analyse\Model;
use Brainworxx\Krexx\Analyse\Routing\AbstractRouting;
use Brainworxx\Krexx\Analyse\Scalar\AbstractScalar;
use Brainworxx\Krexx\Analyse\Scalar\ScalarString;
use Brainworxx\Krexx\Service\Config\ConfigConstInterface;
use Brainworxx\Krexx\Service\Factory\Pool;
use Brainworxx\Krexx\Service\Misc\FileinfoDummy;
use finfo;

/**
 * Processing of strings.
 */
class ProcessString extends AbstractRouting implements
    ProcessInterface,
    ProcessConstInterface,
    CallbackConstInterface,
    ConfigConstInterface
{
    /**
     * The model we are currently working on.
     *
     * @var Model
     */
    protected Model $model;

    /**
     * The buffer info class. We use it to get the mimetype from a string.
     *
     * @var \finfo|\Brainworxx\Krexx\Service\Misc\FileinfoDummy
     */
    protected $bufferInfo;

    /**
     * The deeper string analysis.
     *
     * @var \Brainworxx\Krexx\Analyse\Scalar\AbstractScalar;
     */
    protected AbstractScalar $scalarString;

    /**
     * Length threshold, where we do a buffer-info analysis.
     *
     * @var int
     */
    protected int $bufferInfoThreshold = 20;

    /**
     * Caching of the setting SETTING_ANALYSE_SCALAR
     *
     * @var bool
     */
    protected bool $analyseScalar;

    /**
     * Inject the pool and initialize the buffer-info class.
     *
     * @param \Brainworxx\Krexx\Service\Factory\Pool $pool
     */
    public function __construct(Pool $pool)
    {
        parent::__construct($pool);

        // Init the fileinfo class.
        if (class_exists(finfo::class, false)) {
            $this->bufferInfo = new finfo(FILEINFO_MIME);
        } else {
            // Use a "polyfill" dummy, tell the dev that we have a problem.
            $this->bufferInfo = $pool->createClass(FileinfoDummy::class);
            $pool->messages->addMessage('fileinfoNotInstalled');
        }

        $this->analyseScalar = $this->pool->config->getSetting(static::SETTING_ANALYSE_SCALAR);
        if ($this->analyseScalar) {
            $this->scalarString = $pool->createClass(ScalarString::class);
        }
    }

    /**
     * Is this one a string?
     *
     * @param Model $model
     *   The value we are analysing.
     *
     * @return bool
     *   Well, is this a string?
     */
    public function canHandle(Model $model): bool
    {
        $this->model = $model;
        return is_string($model->getData());
    }

    /**
     * Render a dump for a string value.
     *
     * @return string
     *   The rendered markup.
     */
    public function handle(): string
    {
        $originalData = $data = $this->model->getData();

        // Check, if we are handling large string, and if we need to use a
        // preview (which we call "extra").
        // We also need to check for linebreaks, because the preview can not
        // display those.
        $length = $this->retrieveLengthAndEncoding($data);
        if ($length > 50 || strstr($data, PHP_EOL) !== false) {
            $cut = $this->pool->encodingService->encodeString(
                $this->pool->encodingService->mbSubStr($data, 0, 50)
            ) . static::UNKNOWN_VALUE;

            $data = $this->pool->encodingService->encodeString($data);

            $this->model->setHasExtra(true)
                ->setNormal($cut)
                ->setData($data);
        } else {
            $this->model->setNormal($this->pool->encodingService->encodeString($data));
        }

        if ($this->analyseScalar) {
            return $this->handleStringScalar($originalData);
        }

        return $this->pool->render->renderExpandableChild($this->dispatchProcessEvent($this->model));
    }

    /**
     * Inject the scalar analysis callback and handle possible recursions.
     *
     * @param string $originalData
     *   The original, unprocessed and unescape string.
     *
     * @return string
     *   The generated DOM.
     */
    protected function handleStringScalar(string $originalData): string
    {
        $this->scalarString->handle($this->model, $originalData);
        $domId = $this->model->getDomid();
        if ($domId !== '' && $this->pool->recursionHandler->isInMetaHive($domId)) {
            return $this->pool->render->renderRecursion($this->model);
        }

        $this->pool->recursionHandler->addToMetaHive($domId);
        return $this->pool->render->renderExpandableChild($this->dispatchProcessEvent($this->model));
    }

    /**
     * Retrieve the length and set the encoding in the model.
     *
     * @param string $data
     *   The string of which we want ot know the length and encoding.
     *
     * @return int
     *   the length of the string.
     */
    protected function retrieveLengthAndEncoding(string $data): int
    {
        $encoding = $this->pool->encodingService->mbDetectEncoding($data);
        $messages = $this->pool->messages;

        if ($encoding === false) {
            // Looks like we have a mixed encoded string.
            $length = $this->pool->encodingService->mbStrLen($data);
        } else {
            // Normal encoding, nothing special here.
            $length = $this->pool->encodingService->mbStrLen($data, $encoding);
        }

        // Long string or with broken encoding.
        if ($length > $this->bufferInfoThreshold) {
            // Let's see, what the buffer-info can do with it.
            $this->model->addToJson($messages->getHelp('metaMimeTypeString'), $this->bufferInfo->buffer($data));
        } elseif ($encoding === false) {
            // Short string with broken encoding.
            $this->model->addToJson($messages->getHelp('metaEncoding'), 'broken');
        } else {
            // Short string with normal encoding.
            $this->model->addToJson($messages->getHelp('metaEncoding'), $encoding);
        }

        $this->model->setType(static::TYPE_STRING)->addToJson($messages->getHelp('metaLength'), (string)$length);

        return $length;
    }
}