bmorr75
November 21, 2025, 2:05pm
1
I’m trying to override a Concrete 9.4.4 core file (concrete/src/Config/FileSaver.php) and it is not working. The attempted override is not overriding the core file. Here is my code (located in applicaton/src/Concrete/Config/FileSaver.php):
namespace Application\Concrete\Config;
use Concrete\Core\Config\FileSaver as CoreFileSaver;
class FileSaver extends CoreFileSaver
{
public function save($item, $value, $environment, $group, $namespace = null)
{
// custom code
$result = parent::save($item, $value, $environment, $group, $namespace);
// custom code
return $result;
}
}
That file path does not exist, Application\Config does though.
Maybe try changing the namespace to Application\Config;
bmorr75
November 21, 2025, 2:48pm
3
Unfortunately, that didn’t work either. Thanks.
mhawke
November 22, 2025, 5:55pm
4
Just chiming in to make sure you have Overrides caching off in the Dashboard.
Only a small set of files can be overridden this way. I don’t think Config is one of them.
This tutorial shows how to specifically override the core logger:
Also you might not need to override it depending on what you’re trying to achieve.
Can you tell us more?
bmorr75
November 23, 2025, 2:30am
6
Overrides caching is set to off.
As you said, I checked the documentation and it doesn’t appear that Config can be overridden. I really don’t want to change the core file, but will if I have to.
I’m trying to log the username of any user that makes a change to the configuration. I’m definitely open to other ways of doing it.
Thanks for the help given so far!
Can you explain your application. This seems like a strange class to override. With some knowledge of what you are aiming to achieve one of us may be able to direct you to other solutions.
bmorr75
November 24, 2025, 2:31pm
8
I’m trying to log the username of any user that makes a change to the configuration. I’m definitely open to other ways of doing it.
The Config system is used for other storage as well as stuff that originates from user action in the dashboard. Some is in files and some is in a database table. You could be overwhelmed with unwanted log entries or an entry for every granule of data saved. As well as the dashboard, some blocks use Config to keep track of global options.
My first thought is to consider an on_start event handler (not well considered - others may have better ideas) : IF in_dashboard and the request has POST or GET parameter data, then log it. The log already has columns for page and user. So how much you log is up to you. You would probably want to filter out things like ccm tokens and general dashboard background stuff. You may also need to catch ajax requests with data and filter out anything to do with logging so it doesn’t get stuck in a loop.
mlocati
November 25, 2025, 9:29am
10
The configuration initialization occurs at a very early stage in the bootstrap process of ConcreteCMS.
I think the only viable way to do that is via the application/bootstrap/start.php file.
In that file you should have something like this:
<?php
use Concrete\Core\Application\Application;
$app = new Application();
// ...etcetera...
you can tell Concrete to use your own class when a configuration setting is saved: simply replace the lines above with:
<?php
use Concrete\Core\Application\Application;
use Concrete\Core\Config\SaverInterface;
use Concrete\Core\User\User;
class MySaver implements SaverInterface
{
/**
* @var SaverInterface
*/
private $actualSaver;
/**
* @var Application
*/
private $app;
public function __construct(SaverInterface $actualSaver, Application $app)
{
$this->actualSaver = $actualSaver;
$this->app = $app;
}
/**
* {@inheritdoc}
*
* @see \Concrete\Core\Config\SaverInterface::save()
*/
public function save($item, $value, $environment, $group, $namespace = null)
{
$user = $this->app->make(User::class);
// do whatever you want
$userName = $user->isRegistered() ? $user->getUserName() : '<anonymous>';
$valueSerialized = json_encode($value, JSON_PRETTY_PRINT);
$logMessage = <<<EOT
User: {$userName}
Environment: {$environment}
Namesmapce: {$namespace}
Key: {$item}
New value: {$valueSerialized}
EOT
;
// Store $logMessage somewhere
return $this->actualSaver->save($item, $value, $environment, $group, $namespace);
}
}
$app = new Application();
$app->extend(
SaverInterface::class,
static function(SaverInterface $saver, Application $app) {
return new MySaver($saver, $app);
}
);
// ...etcetera...
bmorr75
November 26, 2025, 4:47pm
11
Thanks! This works! Is there a way to move the MySaver class into a separate file in the application folder?
mlocati
November 26, 2025, 5:52pm
12
Sure!
You can save your classes under application/src/Concrete, and their namespace must be Application\Concrete.
For example, you can define the class Application\Concrete\MySaver in the file application/src/Concrete/MySaver.php containing:
<?php
namespace Application\Concrete;
class MySaver
{
// ...
}
Of course, you can use sub-directories, mapped to sub-namespace names.
For example you could store the class Application\Concrete\Config\MySaver in the file application/src/Concrete/Config/MySaver.php containing:
<?php
namespace Application\Concrete\Config;
class MySaver
{
// ...
}
If you don’t like the Application prefix of the namespace, you can set/add something like this to the application/config/app.php file:
<?php
return [
'namespace' => 'MyWonderfulNamespace',
];
Then you can you can define the class MyWonderfulNamespace\Concrete\Config\MySaver in the file application/src/Concrete/Config/MySaver.php containing:
<?php
namespace MyWonderfulNamespace\Concrete\Config;
class MySaver
{
// ...
}
(I’m 99% sure the Concrete part of the namespace and file path must be present, unless you configure a custom autoloader).
And double check case sensitivity, as in the examples above…
bmorr75
November 26, 2025, 6:08pm
13
I already attempted it and it doesn’t seem to be working. Do I need to modify anything in the “application/bootstrap/start.php” file?
I moved the class out and I’m no longer seeing changes to the configuration in the log. I’m also not seeing any errors.
mlocati
November 26, 2025, 6:23pm
14
What’s the path and name of the file where you stored your class?
What’s its namespace and class name?
Could you share the relevant section of your application/bootstrap/start.php file?
bmorr75
November 26, 2025, 6:32pm
15
Stored the class Application\Concrete\Config\MySaver in the file application/src/Concrete/Config/MySaver.php.
The namespace is “Application\Concrete\Config”.
In the application/bootstrap/start.php file:
use Concrete\Core\Application\Application;
use Application\Concrete\Config;
$app = new Application();
$app->detectEnvironment(
array(
'local' => array(
'hostname',
),
'production' => array(
'live.site',
),
));
$app->extend(
SaverInterface::class,
static function(SaverInterface $saver, Application $app) {
return new MySaver($saver, $app);
}
);
return $app
mlocati
November 26, 2025, 6:37pm
16
You have
use Application\Concrete\Config;
//...
return new MySaver(...);
That’s not correct. You can use one of the following two alternatives:
use Application\Concrete\Config;
//...
return new Config\MySaver(...);
or
use Application\Concrete\Config\MySaver;
//...
return new MySaver(...);
mlocati
November 26, 2025, 6:38pm
17
Also, be sure you have this line too:
use Concrete\Core\Config\SaverInterface;
bmorr75
November 26, 2025, 6:42pm
18
I have that line in the MySaver.php file. Is that correct?
Also, I tried both of your suggestions above and it is still not working.
bmorr75
November 26, 2025, 7:17pm
19
Disregard. I figured it out mostly what you provided so far and correcting my mistakes. Thanks again for everyone’s help!
Here is what I put in the application/bootstrap/start.php file:
<?php
use Concrete\Core\Application\Application;
use Concrete\Core\Config\SaverInterface;
use Application\Concrete\Config\MySaver;
$app = new Application();
$app->detectEnvironment(
array(
'local' => array(
'hostname',
),
'production' => array(
'live.site',
),
));
$app->extend(
SaverInterface::class,
static function(SaverInterface $saver, Application $app) {
return new MySaver($saver, $app);
}
);
return $app;
Here is what I put in the application/src/Concrete/Config/MySaver.php file:
<?php
namespace Application\Concrete\Config;
use Concrete\Core\Config\SaverInterface;
use Concrete\Core\User\User;
use Concrete\Core\Application\Application;
class MySaver implements SaverInterface
{
private $actualSaver;
private $app;
public function __construct(SaverInterface $actualSaver, Application $app)
{
$this->actualSaver = $actualSaver;
$this->app = $app;
}
public function save($item, $value, $environment, $group, $namespace = null)
{
$user = $this->app->make(User::class);
$userName = $user->isRegistered() ? $user->getUserName() : '<anonymous>';
$valueSerialized = json_encode($value, JSON_PRETTY_PRINT);
$logMessage = <<<EOT
User: {$userName}
Environment: {$environment}
Namespace: {$namespace}
Key: {$item}
New value: {$valueSerialized}
EOT
;
\Log::addInfo(t('The following configuration changes were made: %s.', $logMessage));
return $this->actualSaver->save($item, $value, $environment, $group, $namespace);
}
}