Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assets improved #138

Closed
wants to merge 28 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
fb9e972
New theme locator to find themes path in the project
adrienrn Nov 10, 2015
bfcaae4
New themes:install command to make assets available in web/ (just lik…
adrienrn Nov 10, 2015
261b8b7
Renamed command to assets:themes-install
adrienrn Nov 10, 2015
3536410
Clean assets:themes-install command + use liip_theme.themes
adrienrn Nov 10, 2015
acf5ed2
Use ActiveTheme::getThemes()
adrienrn Nov 10, 2015
9122e59
Making liip_theme.themes optional by discovering themes dynamically
adrienrn Nov 10, 2015
297aeab
New Installer class, makes installing assets available outside consol…
adrienrn Nov 12, 2015
c4d2a8e
Changed originDir to match the public/ directory inside each theme
adrienrn Nov 12, 2015
a894883
Sanitizing bundle names to match assets:install (stripping 'bundle').
adrienrn Nov 12, 2015
e5dc7e6
Fix namespace bug for Finder in hardCopy mode
adrienrn Nov 12, 2015
d0f866b
Pass --symlink option to installAssets
adrienrn Nov 12, 2015
4ed2706
Logging added (use -v to display them in console)
adrienrn Nov 12, 2015
e52df2b
Documentation for new classes
adrienrn Nov 12, 2015
a3c2a28
Error handling: target path not writable or missing public/ folder
adrienrn Nov 12, 2015
005dc9c
Fix bug on non-existing basePath + default path platform compatibility
adrienrn Nov 12, 2015
28bb8fe
Fix indentation (PSR-2)
adrienrn Nov 12, 2015
bb1135e
Help for assets:themes-install command
adrienrn Nov 12, 2015
0c6627e
Only discover themes when %liip_theme.themes% is not defined
adrienrn Nov 13, 2015
f51430e
Fix bug when theme does not exists + add warning to notify user
adrienrn Nov 13, 2015
14a8867
Apply StyleCI fixes
adrienrn Nov 13, 2015
7aa9324
Apply StyleCI fixes again.
adrienrn Nov 13, 2015
1d3e0d5
Apply StyleCI fixes (again-again)
adrienrn Nov 13, 2015
2140ca5
Fixes for PR138 (https://github.com/liip/LiipThemeBundle/pull/138)
adrienrn Nov 29, 2015
6be893e
ThemeLocator: Removes duplicate values from theme paths (discoverThemes)
adrienrn Jan 25, 2016
028d4fa
Installer: add 'X' as $dir (@TODO)
adrienrn Jan 25, 2016
006a04a
check if is empty
Morgan-pepe Jan 26, 2016
b89bc7f
set theme == nul
Morgan-pepe Jul 5, 2016
5847668
Merge pull request #1 from adrienrn/fix
Morgan-pepe Jul 5, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion ActiveTheme.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Liip\ThemeBundle;

use Liip\ThemeBundle\Helper\DeviceDetectionInterface;
use Liip\ThemeBundle\Locator\ThemeLocator;

/**
* Contains the currently active theme and allows to change it.
Expand Down Expand Up @@ -42,8 +43,12 @@ class ActiveTheme
* @param array $themes
* @param Helper\DeviceDetectionInterface $deviceDetection
*/
public function __construct($name, array $themes = array(), DeviceDetectionInterface $deviceDetection = null)
public function __construct($name, array $themes = array(), DeviceDetectionInterface $deviceDetection = null, ThemeLocator $themeLocator = null)
{
if (empty($themes) && !is_null($themeLocator)) {
// If no available themes are set in the config and a themeLocator exists
$themes = $themeLocator->discoverThemes();
}
$this->setThemes($themes);

if ($name) {
Expand Down Expand Up @@ -77,6 +82,11 @@ public function getName()

public function setName($name)
{
if (null === $name) {
$this->name = null;
return;
}

if (!in_array($name, $this->themes)) {
throw new \InvalidArgumentException(sprintf(
'The active theme "%s" must be in the themes list (%s)',
Expand Down
108 changes: 108 additions & 0 deletions Command/ThemesInstallCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php

/*
* This file is part of the Liip/ThemeBundle
*
* (c) Liip AG
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Liip\ThemeBundle\Command;

use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Command that installs themes assets into the web/ folder.
*
* @author adrienrn
*/
class ThemesInstallCommand extends ContainerAwareCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('assets:themes-install')
->setDefinition(array(
new InputArgument('target', InputArgument::OPTIONAL, 'The target directory', 'web'),
))
->addOption('symlink', null, InputOption::VALUE_NONE, 'Symlinks the assets instead of copying it')
->setDescription('Installs themes assets into the web directory')
->setHelp(<<<EOT
The <info>%command.name%</info> command installs themes assets into a given
directory (e.g. the <comment>web</comment> directory).

<info>php %command.full_name% web</info>

A "themes" directory will be created inside the target directory and the
"themes/<options=bold>%theme_name%</>/public" directory of each theme will be copied into it.

To create a symlink to each bundle instead of copying its assets, use the
<info>--symlink</info> option (will fall back to hard copies when symbolic links aren't possible:

<info>php %command.full_name% web --symlink</info>

EOT
)
;
}

/**
* {@inheritdoc}
*
* @throws \InvalidArgumentException When the target directory does not exist or symlink cannot be used
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
// Target directory.
$targetArg = rtrim($input->getArgument('target'), DIRECTORY_SEPARATOR);
if (!is_dir($targetArg)) {
throw new \InvalidArgumentException(sprintf('The target directory "%s" does not exist.', $input->getArgument('target')));
}

// Target themes assets directory.
$themesAssetsDir = $targetArg.DIRECTORY_SEPARATOR.'themes';
if (file_exists($themesAssetsDir)) {
$this->getContainer()->get('filesystem')->remove($themesAssetsDir);
}

// Retrieve the active theme.
$activeTheme = $this->getContainer()->get('liip_theme.active_theme');
$availableThemes = $activeTheme->getThemes();


if (!empty($availableThemes)) {
$installedThemes = array();

// Logging install mode.
if ($input->getOption('symlink')) {
$output->writeLn(sprintf('Trying to install theme assets as <comment>symbolic links</comment> in <info>%s</info>.', $themesAssetsDir));
} else {
$output->writeLn(sprintf('Installing theme assets as <comment>hard copies</comment> in <info>%s</info>.', $themesAssetsDir));
}

// Logging list of discovered themes.
$output->writeLn(sprintf('Found following theme(s) to install: <comment>%s</comment>.', implode(', ', $availableThemes)));
foreach ($availableThemes as $theme) {
// Install assets for this theme.
$installed = $this->getContainer()->get('liip_theme.installer')->installAssets($theme, $themesAssetsDir, $input->getOption('symlink'));
if ($installed === true) {
array_push($installedThemes, $theme);
}
}

$output->writeLn(sprintf('<info>Successfully installed assets for %d theme(s).</info>', count($installedThemes)));
} else {

$output->writeLn('<comment>No themes to install.</comment>');
}
}
}
159 changes: 159 additions & 0 deletions Installer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
<?php

/*
* This file is part of the Liip/ThemeBundle
*
* (c) Liip AG
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Liip\ThemeBundle;

use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use Liip\ThemeBundle\Locator\ThemeLocator;
use Psr\Log\LoggerInterface;

/**
* Theme installer service.
*
* This is a service so we can inject it as reference to different parts of the
* application. Can be used from command-line using assets:themes-install or to
* install assets after uploading a new theme in the app.
*
* @author adrienrn
*/
class Installer
{
/**
* Locator service for themes.
*
* @var \Liip\ThemeBundle\Locator\ThemeLocator
*/
protected $themeLocator;

/**
* Symfony filesystem service.
*
* @var \Symfony\Component\Filesystem\Filesystem
*/
protected $filesystem;

/**
* Logger.
* Useful since Symfony 2.4 to show output when launching from console.
*
* @var \Psr\Log\LoggerInterface
*/
protected $logger;

public function __construct(ThemeLocator $themeLocator, Filesystem $filesystem, LoggerInterface $logger = null)
{
$this->themeLocator = $themeLocator;
$this->filesystem = $filesystem;
$this->logger = $logger;
}

/**
* Install assets for given $theme in $basePath.
*
* @param string $theme Name of the theme
* @param string $basePath Path to the target directory, defaults to 'web/themes'
* @param bool $symlink Whether make a symlink or hard copy
*/
public function installAssets($theme, $basePath = null, $symlink = true)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is rather long, maybe some parts can be moved elsewhere?

{
if (is_null($basePath)) {
$basePath = 'web'.DIRECTORY_SEPARATOR.'themes';
}

if (file_exists($basePath) && !is_writable($basePath)) {
throw new \InvalidArgumentException(
"'basePath' is not writable"
);
}

if (!file_exists($basePath)) {
// Create base target directory if needed.
$this->filesystem->mkdir($basePath, 0777);
}

// Search in bundles first.
$pathInfos = $this->themeLocator->locateThemeInBundles($theme, 'X' /* @TODO */);
if (!empty($pathInfos)) {
// Found theme in bundle.
$originDir = $pathInfos['path'];

// Prepare the directory for this bundle.
$themesAssetsBundleDir = $this->getBundleThemesAssetsPath($basePath, $pathInfos['bundle']->getName());
if (!is_dir($themesAssetsBundleDir)) {
$this->filesystem->mkdir($themesAssetsBundleDir, 0777);
}

$targetDir = $themesAssetsBundleDir.DIRECTORY_SEPARATOR.$theme;

$this->logger->notice(sprintf('Found theme <comment>%s</comment> in bundle <comment>%s</comment> installing in <comment>%s</comment>', $theme, $pathInfos['bundle']->getName(), $targetDir));
} else {
// Search in app/
$path = $this->themeLocator->locateThemeInApp($theme);
if ($path) {
$originDir = $path;
$targetDir = $basePath.DIRECTORY_SEPARATOR.$theme;

$this->logger->notice(sprintf('Found theme <comment>%s</comment> in <comment>%s</comment> installing in <comment>%s</comment>', $theme, $originDir, $targetDir));
}
}

if (isset($originDir) && isset($targetDir)) {
// Only link / mirror the public folder.
$originDir = realpath($originDir).DIRECTORY_SEPARATOR.'public';

if (!is_dir($originDir)) {
$this->logger->warning(sprintf('No assets to install for theme %s. <comment>Skipping.</comment>', $theme));

return false;
}

if ($symlink) {
// Symlink.
$this->filesystem->symlink($originDir, $targetDir, true);
} else {
// Hard copy.
$this->hardCopy($originDir, $targetDir);
}

return true;
}

$this->logger->warning(sprintf('Theme <comment>%s</comment> not found. <comment>Skipping.</comment>', $theme));
}

/**
* Get the path for assets of themes from bundles.
*
* @param string $basePath
* @param string $bundleName
*
* @return string
*/
public function getBundleThemesAssetsPath($basePath, $bundleName)
{
return $basePath.DIRECTORY_SEPARATOR.preg_replace('/bundle$/', '', strtolower($bundleName));
}

/**
* Mirrors the content of $originDir in $targetDir
* Inspired by symfony assets:install hardCopy.
*
* @param string $originDir
* @param string $targetDir
*/
private function hardCopy($originDir, $targetDir)
{
$this->filesystem->mkdir($targetDir, 0777);
// We use a custom iterator to ignore VCS files
$this->filesystem->mirror($originDir, $targetDir, Finder::create()->ignoreDotFiles(false)->in($originDir));
}
}
Loading