Question: How can we assign a theme in Magento 2.1 to a store using setup scripts?

Thank you

Answer: 
On Magento 2.1 and later (2.2 and 2.3 coming out) it is recommended to use service contract so I tried doing this without calling method in the model directly.

Unfortunately at this point there is no straight forward way in the core Magento\_Theme module service contract so we still have to make do with using some factory class.

First we need to inject the following classes to the setup script contructor:

```
use Magento\Theme\Api\DesignConfigRepositoryInterface;
use Magento\Theme\Model\Data\Design\ConfigFactory;
use Magento\Theme\Model\ResourceModel\Theme\CollectionFactory;

public function __construct(
        DesignConfigRepositoryInterface $designConfigRepository,
        CollectionFactory $themeCollectionFactory,
        ConfigFactory $themeConfigFactory) {...}

```

Next we will try to load the theme ID from it's path. Then we create a Design Config object by using factory class (hopefully Magento core will provide a service contract to do this in the future). Finally we use the ConfigRepository to save the value.

In this example my theme is for the frontend area, and has path MyVendorName/MyThemeName. 

```
if (version_compare($context->getVersion(), '1.0.0', '<')) {
    $themeCollection = $this->themeCollectionFactory->create();
    $theme = $themeCollection->getThemeByFullPath('frontend/MyVendorName/MyThemeName');
    $themeId = $theme->getId();

    $designConfigData = $this->themeConfigFactory->create('default', 0, ['theme_theme_id' => $themeId]);

    $this->designConfigRepository->save($designConfigData);
}

```

Notes: the designConfigRepository should take care of reindexing the grid.

Using this approach you can also change other theme configuration, for example:

```
$designConfigData = $this->themeConfigFactory->create('default', 0, [
'theme_theme_id' => $themeId,
'head_default_title' => 'My Default Title',
'head_demonotice' => 1 // Display demo store notice
]);

```

Obviously you can replace 'default' and '0' with relevant store scope. Hope this helps.
Better to use `\Magento\Framework\View\Design\Theme\ListInterface` instead of `\Magento\Theme\Model\ResourceModel\Theme\CollectionFactory`. **ListInterface** have method **getThemeByFullPath**, so your code would be:

```
<?php
namespace Vendor\Module\Setup;

use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Store\Model\Store;

/**
 * Class InstallData
 */
class InstallData implements InstallDataInterface
{
    const THEME_FULL_PATH = 'frontend/Vendor/theme';

    /**
     * @var \Magento\Theme\Model\Config
     */
    private $config;

    /**
     * @var \Magento\Framework\View\Design\Theme\ListInterface $themeList
     */
    private $themeList;

    /**
     * InstallData constructor.
     *
     * @param \Magento\Framework\View\Design\Theme\ListInterface $themeList
     * @param \Magento\Theme\Model\Config $config
     */
    public function __construct(
        \Magento\Framework\View\Design\Theme\ListInterface $themeList,
        \Magento\Theme\Model\Config $config
    ) {
        $this->themeList = $themeList;
        $this->config = $config;
    }

    /**
     * @param ModuleDataSetupInterface $setup
     * @param ModuleContextInterface $context
     * @return void
     */
    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $setup->startSetup();

        $this->assignTheme();

        $setup->endSetup();
    }

    /**
     * Assign Theme
     *
     * @return void
     */
    protected function assignTheme()
    {
        /** @var \Magento\Framework\View\Design\ThemeInterface $theme */
        $theme = $this->themeList->getThemeByFullPath(self::THEME_FULL_PATH);

        if ($theme->getId()) {
            $this->config->assignToStore($theme, [Store::DEFAULT_STORE_ID], ScopeConfigInterface::SCOPE_TYPE_DEFAULT);
        }
    }
}

```

And you should add di.xml to your module

```
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Vendor\Module\Setup\InstallData">
        <arguments>
            <argument name="themeList" xsi:type="object">Magento\Theme\Model\ResourceModel\Theme\Collection</argument>
        </arguments>
    </type>
</config> 

```