I've updated a project to the latest version of Craft and enabled project config control. When I make changes locally I'm seeing values such as...
siteSettings:
215a576d-d6b9-41cf-bff5-d7306aa1d646:
hasUrls: '1'
But when I apply this config to our staging environment these are changed to
siteSettings:
215a576d-d6b9-41cf-bff5-d7306aa1d646:
hasUrls: true
Because this change occurs I'm unable to set "allowAdminChanges" => false as I receive an error saying changes to the project config are "read-only".
Can you look for the read-only error in your staging server’s storage/logs/ folder and post the stack trace?
Sure! So when I first apply the project config I get this error in staging:

Then I receive the "Changes to the project config are not possible while in read-only mode" error when I choose "Use project.yaml"
And here's the stack trace:
2019-01-23 11:12:43 [-][1][-][error][yii\base\NotSupportedException] yii\base\NotSupportedException: Changes to the project config are not possible while in read-only mode. in /ROOT/vendor/craftcms/cms/src/services/ProjectConfig.php:330
Stack trace:
#0 /ROOT/vendor/craftcms/cms/src/services/Matrix.php(285): craft\services\ProjectConfig->set('matrixBlockType...', Array)
#1 /ROOT/vendor/craftcms/cms/src/services/Matrix.php(601): craft\services\Matrix->saveBlockType(Object(craft\models\MatrixBlockType), false)
#2 /ROOT/vendor/craftcms/cms/src/fields/Matrix.php(715): craft\services\Matrix->saveSettings(Object(craft\fields\Matrix), false)
#3 /ROOT/vendor/craftcms/cms/src/services/Fields.php(1519): craft\fields\Matrix->afterSave(false)
#4 /ROOT/vendor/craftcms/cms/src/services/Fields.php(817): craft\services\Fields->applyFieldSave('e6640bd5-e054-4...', Array, 'global')
#5 /ROOT/vendor/craftcms/cms/src/services/ProjectConfig.php(815): craft\services\Fields->handleChangedField(Object(craft\events\ConfigEvent))
#6 [internal function]: craft\services\ProjectConfig->craft\services\{closure}(Object(craft\events\ConfigEvent))
#7 /ROOT/vendor/yiisoft/yii2/base/Component.php(627): call_user_func(Object(Closure), Object(craft\events\ConfigEvent))
#8 /ROOT/vendor/craftcms/cms/src/services/ProjectConfig.php(517): yii\base\Component->trigger('updateItem', Object(craft\events\ConfigEvent))
#9 /ROOT/vendor/craftcms/cms/src/helpers/ProjectConfig.php(63): craft\services\ProjectConfig->processConfigChanges('fields.e6640bd5...')
#10 /ROOT/vendor/craftcms/cms/src/services/Matrix.php(305): craft\helpers\ProjectConfig::ensureAllFieldsProcessed()
#11 /ROOT/vendor/craftcms/cms/src/services/ProjectConfig.php(815): craft\services\Matrix->handleChangedBlockType(Object(craft\events\ConfigEvent))
#12 [internal function]: craft\services\ProjectConfig->craft\services\{closure}(Object(craft\events\ConfigEvent))
#13 /ROOT/vendor/yiisoft/yii2/base/Component.php(627): call_user_func(Object(Closure), Object(craft\events\ConfigEvent))
#14 /ROOT/vendor/craftcms/cms/src/services/ProjectConfig.php(517): yii\base\Component->trigger('updateItem', Object(craft\events\ConfigEvent))
#15 /ROOT/vendor/craftcms/cms/src/services/ProjectConfig.php(846): craft\services\ProjectConfig->processConfigChanges('matrixBlockType...')
#16 /ROOT/vendor/craftcms/cms/src/services/ProjectConfig.php(402): craft\services\ProjectConfig->_applyChanges(Array)
#17 /ROOT/vendor/craftcms/cms/src/controllers/ConfigSyncController.php(57): craft\services\ProjectConfig->applyYamlChanges()
#18 [internal function]: craft\controllers\ConfigSyncController->actionApplyYamlChanges()
#19 /ROOT/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)
#20 /ROOT/vendor/yiisoft/yii2/base/Controller.php(157): yii\base\InlineAction->runWithParams(Array)
#21 /ROOT/vendor/craftcms/cms/src/web/Controller.php(109): yii\base\Controller->runAction('apply-yaml-chan...', Array)
#22 /ROOT/vendor/yiisoft/yii2/base/Module.php(528): craft\web\Controller->runAction('apply-yaml-chan...', Array)
#23 /ROOT/vendor/craftcms/cms/src/web/Application.php(297): yii\base\Module->runAction('config-sync/app...', Array)
#24 /ROOT/vendor/craftcms/cms/src/web/Application.php(722): craft\web\Application->runAction('config-sync/app...')
#25 /ROOT/vendor/craftcms/cms/src/web/Application.php(248): craft\web\Application->_processConfigSyncLogic(Object(craft\web\Request))
#26 /ROOT/vendor/yiisoft/yii2/base/Application.php(386): craft\web\Application->handleRequest(Object(craft\web\Request))
#27 /ROOT/public/index.php(23): yii\base\Application->run()
#28 {main}
2019-01-23 11:12:43 [-][1][-][info][application] $_GET = [
'p' => 'admin/actions/config-sync/apply-yaml-changes'
]
Thanks! Just fixed this for the next release.
You can patch your local install by changing your craftcms/cms requirement in composer.json to:
"require": {
"craftcms/cms": "dev-develop#6733f86f8a56f0dba61d84d2fa1124b3fad87aee as 3.1.3",
"...": "..."
}
and then run composer update.
You guys are so dang fast, thanks a ton!
When migrating from Craft 3 to 3.1, the values in project,yaml were like that:
required: '0'
sortOrder: '2'
But if I save a section, field or anything in the control panel in local, the values change to that:
required: false
sortOrder: 2
Why is there this inconsistency? Also, is there a way to regenerate all the project.yaml to have the same format everywhere in the file (boolean and int instead of strings)?
Thanks!
It changes based on where the data is coming from. In the initial config generation it’s coming from the database, and if you’re using MySQL, then “boolean” values will be represented as '1' or '0' (as MySQL doesn’t have a boolean column type), and other numeric values will also come back as strings, despite having numeric column types.
If the data is coming from a POST request, then we tend to typecast the post data to actual booleans/numbers.
We have considered normalizing DB data when querying it, but it would be a ton of effort and/or it would slow everything down, depending on how we implemented it. (Active Record classes do a decent job of auto-typecasting for example, but it does so by running additional queries to the DB to learn about the schema, and storing all that data, so it comes at a performance cost.)
It’s only an issue for MySQL, whereas PostgreSQL always has the correct types, both because it does support a boolean column type, and because the PostgreSQL PDO implementation auto-typecasts the values as they’re sent to PHP, based on the column type.
And there’s good news on the horizon for MySQL installs: PHP 7.4 is going to have typed property support, which means that we will be able to normalize the values right at the property level, e.g.
public bool $required;
public int $sortOrder;
Which means the values will be typecasted correctly right as they are assigned to objects, regardless of what the PDO layer gave us.
Ok, thanks a lot for the explanation!
From this and other comments you made on Github, it seems that PostgreSQL would be a good choice for new projects. I'm also excited for typed property support in PHP 7.4!
@aaronbushnell head ups - I just edited @brandonkelly's comment above with the composer.json snippet to use Craft version "3.1.3" instead to "3.0.3", just FYI in case you already used the snippet.
Ah, thanks @andris-sevcenko!
Just merged in #4167 which properly typecasts all core integer and boolean values as they’re saved to the project config. Up to plugin developers to follow suit, but this should take care of most of the awkwardness.
@brandonkelly Thanks for the update, but it seems that some values are still string instead of boolean or integer. For example, after running php craft project-config/rebuild, for the settings for my fields (Assets, Redactor, PlainText, etc.), I have useSingleFolder: '1' or initialRows: '4'. Also, my plugins have enabled: '1'.
Yeah good point, this change won’t affect custom field settings, plugin settings, etc.
Turns out the added complexity is not really worth it. The settings are stored as a json string, so it wouldn't suddenly change from 0 to false between environments or usage scenarios.
I did a project-config/rebuild and the sections still had:
enableVersioning: '1'
propagateEntries: '1'
So maybe the rebuild didn't do the sections or these values are not always typecasted.
@smcyr Doh. Should be all better with the next release