Jump to content

modifying $config property (e.g. siteSettings) from ready.php


Macrura
 Share

Recommended Posts

in my config.php, i setup an empty array for siteSettings like this:

$config->siteSettings = array();

then in my ready.php file i'm array merging some values from a settings table (profields table), in the admin like this:

$st = $pages->get('/settings/')->settings_table;
$settings = array();

foreach($st as $row) {
	if(!$row->value) continue;
	if($row->disable == 1) continue;
	$settings[$row->setting] = $row->value;
}

$config->siteSettings = array_merge($config->siteSettings, $settings);

i'm curious if anyone sees any possible issues with this; it works now and i can access my siteSettings everywhere doing this;

  • Like 7
Link to comment
Share on other sites

I Don't see any issue here. It's IMO a good way of doing things, doing it 'all the time'.

Same thing here. As long as Ryan doesn't add a native setting called "siteSettings" – which seems quite unlikely – all is good  :)

Link to comment
Share on other sites

ok thanks - that's good to hear ! :)

on some previous projects i was getting those values in the _init and just setting variables i could use in templates, but were not available in functions, modules or the admin (such as in runtime markup field).

For this, I had initially tried to add items to the array directly but was running into an "indirect modification of overloaded property" error. After researching that, i solved it by using the array merge; though i am curious if there is a way to add items directly on the fly from a template file, maybe i need to use the _set ?

__set( $key, $value )

Provides direct reference access to set values in the $data array

  • Like 1
Link to comment
Share on other sites

You could also add a custom api variable like that.

$this->wire('variableName', $obj);

In your case it's both config, but if you're adding something different this might even be more appropriate.

so if i wanted to make an api variable called settings, how would i populate it with the object, say from the ready.php, or would i need to create a module?

so would it then be possible to have a wire('settings')->siteTitle sort of thing?, instead of $config->siteSettings['siteTitle']

Link to comment
Share on other sites

  • 1 month later...

hmmm, came across the "indirect modification of overloaded property" error today and found this thread...

thank you lostkobrakai for that snippet

$this->wire('variableName', $obj);

it works, but only as long as i do not try to modify that variable in a template file.

my setup: (delayed output)

_init.php

$test = array('one', 'two', 'three');
$this->wire('testarray', $test);

template XY included via wireRenderFile()

$testarray = wire('testarray');
// $testarray = [one, two, three]

$testarray[] = "four";
// $testarray = [one, two, three, four]

_main.php

// wire('testarray') = [one, two, three]
// why is four not stored in the array?

what i was trying to do is to make some classnames configurable during runtime. i have a repeater matrix for some content blocks. they get rendered into the same parent div and i want to add classes dynamically depending on the items that are contained in the repeater.

my workaround is setting the parent div's classname via

switch($page->template) {
  case 'blog':
    $class = "demo class blog";
    break;
  ...
  default:
    $class = "demo class";
    break;
}

// html
<div class="<?= $class ?>">
  // foreach repeaterfield echo item->render()
</div>

thats not ideal. i would like to set the parent class directly in the file with the code for the field-render like this:

<?php
$democlasses = wire('democlasses');
$democlasses[] = "my-sample-blog-parent-class";
?>
<div>
    // my blog markup
</div> 

any hints how i can get a configurable array in my templates?

until now i just needed some global variables and storing them just like this worked fine:

// _init.php
$config->demovar = "demo";

// template
$config->demovar = "newdemo";

// _main.php
echo $config->demovar; // newdemo

hope i made myself clear :)

edit: i tried with wirearray at first (to have something like parentclass->add('blog') ) but i had the "noinstanceof wire" problem. there was a tread about this some days ago but i was not able to find it any more... any help very welcome

Link to comment
Share on other sites

Maybe of use for someone. I somewhere use a in a Helper module's init();

// site specific configs

$this->wire("config")->site = new StdClass();
// so now you can do
$this->wire("config")->site->someKey = "somevalue";

and use this $config->site->someKey everywhere.

Link to comment
Share on other sites

hi soma,

i was doing exactly this, but i did not get it working with arrays. is your post related to mine?

edit: i think it works as long as i stay inside _init.php but i want to modify the array in template files...

Link to comment
Share on other sites

I could not make use of $this->wire('variableName', $obj); in my template files either, because as bernhard has pointed out, it is not possible to modify the variable.

So I ended up using this:

use ArrayObject;
$sbs_globalData = array(
    'block_counter' => 1,
);
$sbs_globalArrayObject = new ArrayObject($sbs_globalData, ArrayObject::ARRAY_AS_PROPS);
$config->sbs_globals = $sbs_globalArrayObject;

However, I am also interested in utilizing WireArray instead.

  • Like 1
Link to comment
Share on other sites

//_init.php
$testVar = new \stdClass();
wire('testVar', $testVar);

// home.php (or elsewhere)
$testVar->myArray = array(
    'hello' => 'world'
);

echo '<pre>'; var_dump($testVar); echo '</pre>';

This works fine here. Or am I missing something?

Using stdClass can be an issue because you can't add methods to it. If you plan to do so, better using a real class.

  • Like 1
Link to comment
Share on other sites

EDIT: anyone reading this, please note that the variable was undefined because instead of _init/php I used ready.php accidentally, see: https://processwire.com/talk/topic/12198-modifying-config-property-eg-sitesettings-from-readyphp/?p=116746

Thanks tpr,

What we are after is this (at least I am :)  ) :

//_init.php
$testVar = new \stdClass();
$testVar->myArray = array(
    'hello' => 'world'
);
wire('testVar', $testVar);

// home.php (or elsewhere)
echo '<pre>'; var_dump($testVar); echo '</pre>';

This results in "PHP Notice: Undefined variable: testVar in..." in home.php

Edited by szabesz
Link to comment
Share on other sites

Oh, my, I mixed up /site/templates/_init.php and /site/ready.php just because the latter was open in my IDE and I used that.... :( Sorry for this! Sure, in _init.php the variable is available thanks!

Now I have a few posts to edit :)

Link to comment
Share on other sites

Go get a coffee :)

This works too:

// _init.php (mind the underscore)

wire('testArr', array());

$testArr['initValue'] = 'helloworld';
// home.php (no underscores at all)

$testArr['myArr'] = array(
    'first' => 'veryfirst',
    'two' => 'veryfirst'
);

// create variables from $testArr array
extract($testArr);

echo '<pre>'; var_dump($initValue); echo '</pre>';
echo '<pre>'; var_dump($myArr); echo '</pre>';
Edited by tpr
  • Like 2
Link to comment
Share on other sites

@Martijn Geerts: Yeah, although these naming conventions are logical, it is easy to get confused sometimes.
@tpr: Actually, I was drinking my coffee why fiddling with the above code, but doing these two activities at the same time made things worse, I suppose :)

  • Like 1
Link to comment
Share on other sites

ok, finally i got (almost) what i wanted:

// _init.php
// set classes for parent container
$classes = array();
$classes['tm-main'][] = 'tm-section';
$this->wire('classes', $classes);

// blog.php
$classes = $this->wire('classes');
$classes['tm-main'][] = 'tm-blog';
$this->wire('classes', $classes);

// _main.php
<section id="tm-main" class="<?= getClasses('tm-main') ?>">
    <?= $content ?>
</section>

// _func.php
/**
 * render class string for given div
 * 
 * @param string  key of element
 * @return string  class string
 * 
 */
function getClasses($element) {
    $classes = wire('classes');
    return implode(" ", $classes[$element]);
} 

using PW 3.0.12 it did not work with the example of tpr above using wire(x, y) without $this...

i'm still not 100% happy with that solution. i always need to get, set and save the new class in the template files. that seems not the best solution. i tried to create a function addClass($element, $class) with this content:

/**
 * add class to given element
 * 
 * @param string  key of element
 * @param string  class
 * 
 */
function addClass($element, $class) {
    $classes = wire('classes');
    $classes[$element][] = $class;
    wire('classes', $classes);
}

but that does not have any effect.

if anybody could give me some hints what is going on and why, that would be great :)

Link to comment
Share on other sites

@bernhard: I use SPEX module that has support for this sort of things (and more). If the above really does not work for you, you may have a look into SPEX, how it is done there.

It uses two hooks: https://github.com/jdart/Spex/blob/master/Spex.module#L150 & https://github.com/jdart/Spex/blob/master/Spex.module#L170

The relevant parts in the first hook for you are in line 155 157 and 164-165 (the rest is related to a profiler / logging, it is not relevant for you in the initial regard)

If you want to try it out or build something own that need to rely on the method getTemplateVars(), please refer to its support thread (or better to the solution here) for a necessary code change when using it with PW 3.0+

Edited by horst
  • Like 1
Link to comment
Share on other sites

Hi boys,


// _init.php (mind the underscore)
wire('testArr', array());
$testArr['initValue'] = 'helloworld';
// home.php (no underscores at all)
$testArr['myArr'] = array(
    'first' => 'veryfirst',
    'two' => 'veryfirst'
);
// create variables from $testArr array
extract($testArr);
echo '<pre>'; var_dump($initValue); echo '</pre>';
echo '<pre>'; var_dump($myArr); echo '</pre>';

First of all, it is not early morning, so I got back to this one :)

bernhard wrote: "using PW 3.0.12 it did not work with the example of tpr above using wire(x, y) without $this..." Actually, this has nothing to do with PW version, since $testArr is just a local variable, in the scope of the template and not related to the wire object. This way $testArr is not stored as an API variable. To append it to the wire object, we do need to access it via $this. See public function wire($name = '', $value = null, $lock = false) in /wire/core/Wire.php.

The  function wire($name = 'wire')  in /wire/core/Functions.php can only retrieve variables but it cannot set them. So wire('testArr', array()); has no effect. The code only works, because we are dealing with variables in the same scope.

Correct me if I'm mistaken, but I cannot come up with another explanation.

  • Like 1
Link to comment
Share on other sites

thank you szabesz, that makes sense to me. so would it be possible to set a property (right?) of the wire object inside a function in _func.php?

function setPropertyOfWire($key, $val) {
   $this->wire($key, $val);
}

would not work, because $this is the wrong scope. OOP is still quite new to me  :-X

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...