<commit_before><?php

namespace Platformsh\Cli\Service;

use Platformsh\Cli\Util\NestedArrayUtil;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Yaml\Yaml;

class PropertyFormatter implements InputConfiguringInterface
{
    const DEFAULT_DATE_FORMAT = 'c';

    /** @var int */
    public $yamlInline = 2;

    /** @var InputInterface|null */
    protected $input;

    public function __construct(InputInterface $input = null)
    {
        $this->input = $input;
    }

    /**
     * @param mixed  $value
     * @param string $property
     *
     * @return string
     */
    public function format($value, $property = null)
    {
        switch ($property) {
            case 'http_access':
                return $this->formatHttpAccess($value);

            case 'token':
                return '******';

            case 'created_at':
            case 'updated_at':
            case 'ssl.expires_on':
                return $this->formatDate($value);

            case 'ssl':
                if ($property === 'ssl' && is_array($value) && isset($value['expires_on'])) {
                    $value['expires_on'] = $this->formatDate($value['expires_on']);
                }
        }

        if (!is_string($value)) {
            $value = rtrim(Yaml::dump($value, $this->yamlInline));
        }

        return $value;
    }

    /**
     * Add options to a command's input definition.
     *
     * @param InputDefinition $definition
     */
    public static function configureInput(InputDefinition $definition)
    {
        $description = 'The date format (as a PHP date format string)';
        $option = new InputOption('date-fmt', null, InputOption::VALUE_REQUIRED, $description, self::DEFAULT_DATE_FORMAT);
        $definition->addOption($option);
    }

    /**
     * @param string $value
     *
     * @return string
     */
    protected function formatDate($value)
    {
        $format = null;
        if (isset($this->input) && $this->input->hasOption('date-fmt')) {
            $format = $this->input->getOption('date-fmt');
        }
        $format = $format ?: self::DEFAULT_DATE_FORMAT;

        // Workaround for the ssl.expires_on date, which is currently a
        // timestamp in milliseconds.
        if (substr($value, -3) === '000' && strlen($value) === 13) {
            $value = substr($value, 0, 10);
        }

        $timestamp = is_numeric($value) ? $value : strtotime($value);

        return date($format, $timestamp);
    }

    /**
     * @param array|string|null $httpAccess
     *
     * @return string
     */
    protected function formatHttpAccess($httpAccess)
    {
        $info = (array) $httpAccess;
        $info += [
            'addresses' => [],
            'basic_auth' => [],
            'is_enabled' => true,
        ];
        // Hide passwords.
        $info['basic_auth'] = array_map(function () {
            return '******';
        }, $info['basic_auth']);

        return $this->format($info);
    }

    /**
     * @param OutputInterface $output
     * @param array           $data
     * @param string|null     $property
     */
    public function displayData(OutputInterface $output, array $data, $property = null)
    {
        $key = null;

        if ($property) {
            $parents = explode('.', $property);
            $key = end($parents);
            $data = NestedArrayUtil::getNestedArrayValue($data, $parents, $keyExists);
            if (!$keyExists) {
                throw new \InvalidArgumentException('Property not found: ' . $property);
            }
        }

        $this->yamlInline = 10;
        $output->writeln($this->format($data, $key));
    }
}<commit_msg>Document displayData() and tweak YAML formatting<commit_after><?php

namespace Platformsh\Cli\Service;

use Platformsh\Cli\Util\NestedArrayUtil;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Yaml\Yaml;

class PropertyFormatter implements InputConfiguringInterface
{
    const DEFAULT_DATE_FORMAT = 'c';

    /** @var InputInterface|null */
    protected $input;

    public function __construct(InputInterface $input = null)
    {
        $this->input = $input;
    }

    /**
     * @param mixed  $value
     * @param string $property
     *
     * @return string
     */
    public function format($value, $property = null)
    {
        switch ($property) {
            case 'http_access':
                return $this->formatHttpAccess($value);

            case 'token':
                return '******';

            case 'created_at':
            case 'updated_at':
            case 'ssl.expires_on':
                return $this->formatDate($value);

            case 'ssl':
                if ($property === 'ssl' && is_array($value) && isset($value['expires_on'])) {
                    $value['expires_on'] = $this->formatDate($value['expires_on']);
                }
        }

        if (!is_string($value)) {
            $value = rtrim(Yaml::dump($value, 2));
        }

        return $value;
    }

    /**
     * Add options to a command's input definition.
     *
     * @param InputDefinition $definition
     */
    public static function configureInput(InputDefinition $definition)
    {
        $description = 'The date format (as a PHP date format string)';
        $option = new InputOption('date-fmt', null, InputOption::VALUE_REQUIRED, $description, self::DEFAULT_DATE_FORMAT);
        $definition->addOption($option);
    }

    /**
     * @param string $value
     *
     * @return string
     */
    protected function formatDate($value)
    {
        $format = null;
        if (isset($this->input) && $this->input->hasOption('date-fmt')) {
            $format = $this->input->getOption('date-fmt');
        }
        $format = $format ?: self::DEFAULT_DATE_FORMAT;

        // Workaround for the ssl.expires_on date, which is currently a
        // timestamp in milliseconds.
        if (substr($value, -3) === '000' && strlen($value) === 13) {
            $value = substr($value, 0, 10);
        }

        $timestamp = is_numeric($value) ? $value : strtotime($value);

        return date($format, $timestamp);
    }

    /**
     * @param array|string|null $httpAccess
     *
     * @return string
     */
    protected function formatHttpAccess($httpAccess)
    {
        $info = (array) $httpAccess;
        $info += [
            'addresses' => [],
            'basic_auth' => [],
            'is_enabled' => true,
        ];
        // Hide passwords.
        $info['basic_auth'] = array_map(function () {
            return '******';
        }, $info['basic_auth']);

        return $this->format($info);
    }

    /**
     * Display a complex data structure.
     *
     * @param OutputInterface $output     An output object.
     * @param array           $data       The data to display.
     * @param string|null     $property   The property of the data to display
     *                                    (a dot-separated string).
     */
    public function displayData(OutputInterface $output, array $data, $property = null)
    {
        $key = null;

        if ($property) {
            $parents = explode('.', $property);
            $key = end($parents);
            $data = NestedArrayUtil::getNestedArrayValue($data, $parents, $keyExists);
            if (!$keyExists) {
                throw new \InvalidArgumentException('Property not found: ' . $property);
            }
        }

        if (!is_string($data)) {
            $output->write(Yaml::dump($data, 5, 4, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK));
        } else {
            $output->writeln($this->format($data, $key));
        }
    }
}
{'fraction_non_alphanumeric': 0.1409597794762561, 'fraction_numerical': 0.0030071419621601303, 'mean_word_length': 2.067640276710223, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5266118', 'n_tokens_mistral': 2284, 'n_tokens_neox': 2203, 'n_words': 487}