Symfony clear cache component after deploy - caching

Hi is there way to clear ALL cached data from symfony cache component?
Here http://symfony.com/doc/current/components/cache/cache_pools.html on bottom is: (i need console command)
$cacheIsEmpty = $cache->clear();
and command:
bin/console cache:clear
keeps this cache untouched
I am lookig for console command witch i can call in *.sh script every deploy.
EDIT (example):
Default input options:
$cache = new FilesystemAdapter();
$defaultInputOptions = $cache->getItem('mainFilter.defaultInputOptions');
if (!$defaultInputOptions->isHit()) {
// collect data, format etc.
$expiration = new \DateInterval('P1D');
$defaultInputOptions->expiresAfter($expiration);
$cache->save($defaultInputOptions);
} else {
return $defaultInputOptions->get();
}
But if i change something in 'collect data, format etc.' on my machine and after that make deploy (git pull, composer install, bin/console cache:clear...) then new version on server has still valid cache (1 day) and take data from it...

You can make any service you want implement the Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface to be used by symfony native cache:clear
use Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface;
use Symfony\Component\Cache\Adapter\AdapterInterface;
final class SomeCacheClearer implements CacheClearerInterface
{
private $cache;
public function __construct(AdapterInterface $filesystemAdapter)
{
$this->cache = $filesystemAdapter;
}
public function clear($cacheDir)
{
$this->cache->clear();
}
}
Config is done by the tag kernel.cache_clearer
cache_provider.clearer:
class: AppBundle\Path\SomeCacheClearer
arguments:
- 'my_app_cache'
tags:
- { name: kernel.cache_clearer }
EDIT: precision about cache as a service:
Your cache service could be defined like that
my_app_cache:
class: Symfony\Component\Cache\Adapter\FilesystemAdapter
Or if you want to specify a namespace and ttl
my_app_cache:
class: Symfony\Component\Cache\Adapter\FilesystemAdapter
arguments:
- 'my_cache_namespace'
- 30 #cache ttl (in seconds)
So you should not use
$cache = new FilesystemAdapter();
But with service injection
$cache = $this->get('my_app_cache');

At the end - suffices edit only services.yml and add:
appbundle.cachecomponent.clearall:
class: Symfony\Component\Cache\Adapter\FilesystemAdapter
tags:
- { name: kernel.cache_clearer }
I am new in symfony so i hope that is right solution.

Related

Activate two add-ons on prestashop

I want to activate two add-ons on prestashop but i cant activate both i get this error
Cannot enable module blockproductsbycountry. Unable to install override: The method getProductProperties in the class Product is already overridden by the module dynamicproduct
the path
public_html/override/classes/Product.php
provider->isAfter1730()) { $id_product = (int) $row['id_product']; $dynamic_config = classes\models\DynamicConfig::getByProduct($id_product); if ($dynamic_config->active) { $displayed_price = classes\models\DynamicConfig::getDisplayedPrice($id_product); if ($displayed_price || $dynamic_config->display_dynamic_price) { $module->calculator->assignProductPrices($row, $displayed_price, $result); } } } return $result; } }
This happens when a method of a class is overriden by both modules at the same time.
There is no automatic solution for this: you will have to check both overrides and manually merge the code back into the main Prestashop folder (/override/classes/Product.php).
After that you will have to remove the overridden method from the installer of both modules so that you can install/activate/deactivate them as needed without having errors.

Class does not exist by migrate the cacheManager to constructor injection

I have a problem with my cacheManager instance migration into TYPO3 10. According to the TYPO3 10 documentation, the cache should be injected via the constructor instead of an instance of "cacheManager".
I followed the documentation, the yaml config is also correct and I get an error message in the frontend.
"Class TYPO3\CMS\Core\Cache\Frontend\Frontend does not exist. Reflection failed."
As far as I know, this class does not exist at all.
Is there a solution for this error?
EXT:my_ext/Configuration/Services.yaml
services:
cache.my_ext:
class: TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
factory: ['#TYPO3\CMS\Core\Cache\CacheManager', 'getCache']
arguments: ['my_ext']
MyVendor\MyExt\Connection\Http:
arguments:
$cache: '#cache.my_ext'
EXT:my_ext/Classes/Connection/Http.php
/**
* #var FrontendInterface
*/
private $cache;
public function __construct(FrontendInterface $cache)
{
$this->cache = $cache;
}
public function initializeObject() {
$className = explode('\\', get_class($this));
$this->extensionKey = \TYPO3\CMS\Core\Utility\GeneralUtility::camelCaseToLowerCaseUnderscored($className[1]);
}
public function getDataFromUrl($url, $cachingTags = array()) {
$cacheIdentifier = sha1($url);
$remoteData = $this->getUrl($url . "&" . time());
if (($this->cache->get($cacheIdentifier)) === false) {
$this->cache->set($cacheIdentifier, $remoteData, $cachingTags,36000);
}
return $remoteData;
}
I followed the documentation here:
https://docs.typo3.org/m/typo3/reference-coreapi/10.4/en-us/ApiOverview/CachingFramework/Developer/Index.html
In my case, the problem was that in docs there were missing service default configs.
Following is the minimal configuration for me that worked.
services:
_defaults:
autowire: true
autoconfigure: true
public: false
Mohsin\HeadlessProducts\:
resource: '../Classes/*'
cache.headless_products:
class: TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
factory: ['#TYPO3\CMS\Core\Cache\CacheManager', 'getCache']
arguments: ['headless_products']
Mohsin\HeadlessProducts\Utility\ProductsUtility:
arguments:
$cache: '#cache.headless_products'
Also, it's important to remove the cache from the install tool or CLI otherwise your changes will not reflect if you remove it from the backend only.
My solution:
Content of the Services.yaml file
services: _defaults:
autowire: true
autoconfigure: true
public: false
WimRoukema\WrCollection\:
resource: '../Classes/*'
cache.wr_collection:
class: TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
factory: ['#TYPO3\CMS\Core\Cache\CacheManager', 'getCache']
arguments: ['wr_collection']
WimRoukema\WrCollection\Controller\IndexController:
public: true
arguments:
- '#cache.wr_collection'
My solution was not to use different keys in localconf.php.
According to named documentation you should use myext_mycache and my_cache in different places. When I used only my_cache it worked.

Unable to render HTML from Markdown

I am going through an online course on Laravel. This course is using the League\commonmark package for converting markdown to html.
Whenever the package is used in the app, I get:
Unable to find corresponding renderer for block type League\CommonMark\Block\Element\Document
The app uses the following presenter to do the conversion.
class PagePresenter extends AbstractPresenter
{
protected $markdown;
public function __construct($object, CommonMarkConverter $markdown)
{
$this->markdown = $markdown;
parent::__construct($object);
}
public function contentHtml()
{
return $this->markdown->convertToHtml($this->content);
}
}
Can anyone point me in the right direction?
That happens because the IoC is resolving the dependencies for CommonMarkConverter, specifically Environment which is instantiated with all null properties.
You can probably resolve this by using a Laravel specific integration: https://github.com/GrahamCampbell/Laravel-Markdown
Or you can bind and instance to the service container this way:
In your AppServiceProvider, register method add this:
$this->app->singleton('Markdown', function ($app) {
// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
$environment = \League\CommonMark\Environment::createCommonMarkEnvironment();
// Define your configuration:
$config = ['html_input' => 'escape'];
// Create the converter
return new \League\CommonMark\CommonMarkConverter($config, $environment);
});
Now remove CommonMarkConverter from your Presenter constructor add use app('Markdown'):
class PagePresenter extends AbstractPresenter {
protected $markdown;
public function __construct($object)
{
$this->markdown = app('Markdown');
parent::__construct($object);
}
public function contentHtml()
{
return $this->markdown->convertToHtml($this->content);
}
}
You just put a line in the config/app.php file
'Markdown' => GrahamCampbell\Markdown\Facades\Markdown::class,

Symfony2 dynamic routing - caching issue

I'm trying to create dynamic routes as I have created a CMS where each page created can be associated to a route. I'm using the example from this link - http://php-and-symfony.matthiasnoback.nl/2012/01/symfony2-dynamically-add-routes/ and all works fine, however the routing is cached, therefore one route will work but then the next won't unless I clear the cache. Is it possible to remove just the routing cache at this stage or is there another alternative? I don't want to remove the whole cache directory on each page load as that wouldn't make sense. Here is the example code:
namespace Acme\RoutingBundle\Routing;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\Loader\LoaderResolver;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
class ExtraLoader implements LoaderInterface
{
private $loaded = false;
public function load($resource, $type = null)
{
if (true === $this->loaded) {
throw new \RuntimeException('Do not add this loader twice');
}
$routes = new RouteCollection();
$pattern = '/extra';
$defaults = array(
'_controller' => 'AcmeRoutingBundle:Demo:extraRoute',
);
$route = new Route($pattern, $defaults);
$routes->add('extraRoute', $route);
return $routes;
}
public function supports($resource, $type = null)
{
return 'extra' === $type;
}
public function getResolver()
{
}
public function setResolver(LoaderResolver $resolver)
{
// irrelevant to us, since we don't need a resolver
}
}
Then I've made a service for the ExtraLoader:
<!-- in /src/Acme/RoutingBundle/Resources/config/services.xml -->
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="acme.routing_loader" class="Acme\RoutingBundle\Routing\ExtraLoader">
<tag name="routing.loader"></tag>
</service>
</services>
</container>
The last thing we need, is a few extra lines in /app/config/routing.yml:
AcmeRoutingBundle:
resource: .
type: extra
This is quite inefficient, because with each new route you have to clear cache, so you'll be bound by hdd/ssd with useless clear cache.
The alternative is to create a new method in controller which accepts a dynamic page on GET and to show the dynamic content in twig.
You can create a service to render the dynamic pages, which will simplify things.
Do you have looked at the DynamicRouter from the symfony-cmf project? I think this fits your needs and is exactly created for your use case.
You current implementation has some really issues you should know about. First of all, you have to clear the routing cache, for each route you create/edit/delete. This leads to race conditions and memory peaks for no reason.
The default implementation from symfony is to handel static routes, not dynamic ones.
I researched and tried out a bit and I found out that you can just delete the following files:
for dev:
/app/cache/dev/appDevUrlGenerator.php
/app/cache/dev/appDevUrlGenerator.php.meta
/app/cache/dev/appDevUrlMatcher.php
/app/cache/dev/appDevUrlMatcher.php.meta
for prod:
/app/cache/prod/appProdUrlGenerator.php
/app/cache/prod/appProdUrlMatcher.php
There is only one minior downside of this. I am using the current route to determine if a menu item is active or not:
{% set currentPath = path(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')) %}
...
<li{% if currentPath == path('mybundle_default_index') %} class="active"{% endif %}>
In this case app.request.attributes.get('_route') is still cached as a route that might not exist anymore. I don't know yet if this only concerns the twig cache or other parts too.
Also I don't understand why you would have to delete the whole cache on each page load? You only have to clear the cache when new routes are added.
I've resolved this problem in my own CMS.
At first I overrode the base Router class:
parameters:
router.class: Name\Of\Your\Router
and extended it:
use Symfony\Bundle\FrameworkBundle\Routing\Router as BaseRouter;
class Router extends BaseRouter
{
public function clearCache($cache_dir, $environment, $warm_up)
{
$cache_dir .= '/'. $environment;
$environment = ucfirst($environment);
#unlink($cache_dir .'/app'. $environment .'UrlMatcher.php');
#unlink($cache_dir .'/app'. $environment .'UrlGenerator.php');
if ($warm_up) {
$this->matcher = null;
$this->generator = null;
$this->warmUp($cache_dir);
}
}
}
Secondly I created a service CacheService:
cache_service:
class: Name\Of\Your\CacheService
arguments:
- #router
- %kernel.environment%
- %kernel.root_dir%/cache
and added the following method:
public function clearCache($environment = null)
{
if (null === $environment) {
$environment = $this->environment;
}
$this->router->clearCache($this->cache_dir, $environment, $this->environment == $environment);
}
So now I can call this method when I need to clear cache for current or specific environment.

Entity Framework 4.3.1 add-migration error: "model backing the context has changed"

I'm getting an error when trying to run the EF 4.3.1 add-migrations command:
"The model backing the ... context has changed since the database was created".
Here's one sequence that gets the error (although I've tried probably a dozen variants which also all fail)...
1) Start with a database that was created by EF Code First (ie, already contains a _MigrationHistory table with only the InitialCreate row).
2) The app's code data model and database are in-sync at this point (the database was created by CF when the app was started).
3) Because I have four DBContexts in my "Services" project, I didn't run 'enable-migrations' command (it doesn't handle multipe contexts). Instead, I manually created the Migrations folder in the Services project and the Configuration.cs file (included at end of this post). [I think I read this in a post somewhere]
4) With the database not yet changed, and the app stopped, I use the VS EDM editor to make a trivial change to my data model (add one property to an existing entity), and have it generate the new classes (but not modify the database, obviously). I then rebuild the solution and all looks OK (but don't delete the database or restart the app, of course).
5) I run the following PMC command (where "App" is the name of one of the classes in Configuration.cs):
PM> add-migration App_AddTrivial -conf App -project Services -startup Services -verbose
... which fails with the "The model ... has changed. Consider using Code First Migrations..." error.
What am I doing wrong? And does anyone else see the irony in the tool telling me to use what I'm already trying to use ;-)
What are the correct steps for setting-up a solution starting with a database that was created by EF CF? I've seen posts saying to run an initial migration with -ignorechanges, but I've tried that and it doesn't help. Actually, I've spent all DAY testing various permutations, and nothing works!
I must be doing something really stupid, but I don't know what!
Thanks,
DadCat
Configuration.cs:
namespace mynamespace
{
internal sealed class App : DbMigrationsConfiguration
{
public App()
{
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "Services.App.Repository.Migrations";
}
protected override void Seed(.Services.App.Repository.ModelContainer context)
{
}
}
internal sealed class Catalog : DbMigrationsConfiguration<Services.Catalog.Repository.ModelContainer>
{
public Catalog()
{
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "Services.Catalog.Repository.Migrations";
}
protected override void Seed(Services.Catalog.Repository.ModelContainer context)
{
}
}
internal sealed class Portfolio : DbMigrationsConfiguration<Services.PortfolioManagement.Repository.ModelContainer>
{
public Portfolio()
{
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "Services.PortfolioManagement.Repository.Migrations";
}
protected override void Seed(Services.PortfolioManagement.Repository.ModelContainer context)
{
}
}
internal sealed class Scheduler : DbMigrationsConfiguration<.Services.Scheduler.Repository.ModelContainer>
{
public Scheduler()
{
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "Services.Scheduler.Repository.Migrations";
}
protected override void Seed(Services.Scheduler.Repository.ModelContainer context)
{
}
}
}
When using EF Migrations you should have one data context per database. I know that it can grow really large, but by trying to split it you will run into several problems. One is the migration issue that you are experiencing. Later on you will probably be facing problems when trying to make queries joining tables from the different contexts. Don't go that way, it's against how EF is designed.

Resources