Search code examples
phparraysdimensions

Pushing data into an array that's inside of an array


So this probably has been asked before, or I might just be using arrays on a completely weird way. Anyhow, what I'm trying to do is have one array, let's say.. $replacements = array(); This array includes all the data of keys and replacements. Don't know how to describe it but this is how the idea was taken from: click -- Now, let's say I've got this array as stated above, I'm trying to have inside of my function that appends to the array, an option that allows you to make one single key restricted to a dynamic set of pages. This is how I'd imagine the array to look like:

array() {
    ["key1"] => "result"
    ["key2"] => "result2"
    ["key3 etc"] => "result3 etc"
}

That'd be an array of the keys without any page restrictions specified, and this is how I'd imagine the array to be when I've appended additional arrays for page restricted keys.

array() {
    ["key1"] => "result"
    ["key2"] => "result2"
    ["key3 etc"] => "result3 etc"
    "homepage" = array() {
        ["home_key1"] => "this is a key in the homepage only"
        ["two_page_restricted"] => "this is a replacement in two restricted pages only"
    },
    "newspage" = array() {
        ["two_page_restricted"] => "this is a replacement in two restricted pages only"
    }
}

I'm not sure if anything I've said so far makes any sense, but I guess you get the picture.. This is what I've got so far for a basic key replacement:

function addTranslation($key, $replacement, $restricted = null) {
    if($restricted == null)
        array_push($this->translations, $key, $replacement);
    //else 
        //array_push($this->translations, )
    }

In the end, what I'm trying to accomplish is that if $restricted isn't null then append from it to $this->translations without interfering with other keys.. Thanks in advance for any assistance effort.

Edit: If it helps, this is how I'd use the function:

For two pages: $class->addTranslation("{key}", "this is a key", array("homepage", "newspage");

For any page: $class->addTranslation("{key}", "this is a key");

Edit2: For clarifications, this is PHP not JavaScript.


Solution

  • To answer the main question, a method that would handle pushing data either at the root level of an array attribute or at multiple sub levels of that same array at once could look like this:

    class EntryHandler
    {
        private $entries;
    
        function addEntry($key, $value, array $subArrayKeys = null) 
        {
            if($subArrayKeys == null)
            {
                $this->entries[$key] = $value;
                return; // Skip the subArrayKeys handling
            }
    
            foreach($subArrayKeys as $subArrayKey)
            {
                // Initialize the sub array if it does not exist yet
                if(!array_key_exists($subArrayKey, $this->entries))
                {
                    $this->entries[$subArrayKey] = [];
                }
                // Add the value
                $this->entries[$subArrayKey][$key] = $value;
            }
        }
    }
    

    That being said you specified that this appending operation should not "interfere with other keys". In that case, the way you describe the array you expect will simply not do. With such a structure, you would not be able to have a translation key and a restricted page name with the same value.

    I think the right approach here is to have a consistent structure where each level of your multidimensional array contain the same type of data. Considering your use case, you could introduce a "default" domain which is the one you would use as a base for your translations in addition to page specific translations.


    Here is a small class taken from one of my projects that I adapted to fit your use case as I understood it. It uses strtr as suggested in the post you linked for the string processing part.

    class Translator
    {
        const DEFAULT_DOMAIN = '_default'; // A string that you are forbidden to use as a page specific domain name
        const KEY_PREFIX = '{';
        const KEY_SUFFIX = '}';
    
        private $translations = [];    
    
        public function addTranslation($key, $translation, array $domains = null)
        {
            // If no domain is specified, we add the translation to the default domain
            $domains = $domains == null ? [self::DEFAULT_DOMAIN] : $domains;
            foreach($domains as $domain)
            {
                // Initialize the sub array of the domain if it does not exist yet
                if(!array_key_exists($domain, $this->translations))
                {
                    $this->translations[$domain] = [];
                }
    
                $this->translations[$domain][$key] = $translation;
            }
        }
    
        public function process($str, $domain = null)
        {
            return strtr($str, $this->getReplacePairs($domain));
        }
    
        private function getReplacePairs($domain = null)
        {
            // If the domain is null, we use the default one, if not we merge the default 
            // translations with the domain specific ones (the latter will override the default one) 
            $replaceArray = $domain == null 
                ? $this->translations[self::DEFAULT_DOMAIN] ?? [] 
                : array_merge($this->translations[self::DEFAULT_DOMAIN] ?? [], $this->translations[$domain] ?? []);
    
            // Then we add the prefix and suffix for each key
            $replacePairs = [];
            foreach($replaceArray as $baseKey => $translation)
            {
                $replacePairs[$this->generateTranslationKey($baseKey)] = $translation;
            }
    
            return $replacePairs;
        }
    
        private function generateTranslationKey($base)
        {
            return self::KEY_PREFIX . $base . self::KEY_SUFFIX;
        }
    }
    

    With this class, the following code

    $translator = new Translator();
    $translator->addTranslation('title', 'This is the default title');
    $translator->addTranslation('title', 'This is the homepage title', ['homepage']);
    
    $testString = '{title} - {homepage}';
    echo $translator->process($testString, 'random_domain'); // Outputs "This is the default title - {homepage}"
    echo '<hr/>';
    echo $translator->process($testString, 'homepage');  // Outputs "This is the homepage title - {homepage}"
    

    would output:

    This is the default title - {homepage}<hr/>This is the homepage title - {homepage}