Drupal 9 - Code modification doesn't take effect - php

I am trying to debug some code on my Drupal 9 application.
For example, at the file web/index.php, I try to add die('Was here')
<?php
use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;
$autoloader = require_once 'autoload.php';
//My code is here
die('Was here');
$kernel = new DrupalKernel('prod', $autoloader);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
At first, I got the result on my browser. Next I delete this die function, and when i refresh my browser, I get the same as before as if I didn't change the code
After some minutes, the expected result is shown in my browser. So weird
So I am wondering why is Drupal isn't taking that code change into account.
Btw, I run the command drush cr but it didn't change anything

That sounds like PHP OpCode Cache.
You can see if its enabled or not in the Drupal status report under "PHP OPcode caching".
There's a page on on disabling Drupal Caching [here][1] which includes a section on opcache.
I believe to disable opcache you can add an entry to your php.ini file.
opcache.enable=0
Be sure to restart relevant services like php-fpm. And verify it was effective in the Drupal status report.
[1]: https://www.drupal.org/node/2598914

Related

Symfony 5 - Clear cache contract command

use Symfony\Contracts\Cache\ItemInterface;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
$cache = new FilesystemAdapter();
$value = $cache->get('my_cache_key', function (ItemInterface $item) {
$item->expiresAfter(3600);
// ... do some HTTP request or heavy computations
$computedValue = 'foobar';
return $computedValue;
});
I use Symfony 5.4 and the cache contracts on an application and some cache expirations are quite long. My problem is that some values need to be changed and to do it properly, I would need to be able to purge the cache with a command line on my production server to be sure to have correct data.
I can make a custom command ex: php bin/console app:cache:custom-clear that invalidates some tags but I'm surprised I don't have a native command to do this cache purge operation globally.
It may be that it's simple and I didn't understand anything but I don't see much in the doc on this point.
If anyone has a lead, I'm interested.

How to use composer/composer PHP classes to update individual packages

I want to use the composer/composer PHP classes to update individual plugin packages.
I do not want to use command-line solutions like exec("php composer.phar update");
I am unable to get it to work. I have tried several different options, much alike the following code.
It just returns a blank screen.
use Composer\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;
$input = new ArrayInput(array('command' => 'require vendor/packkage dev-master'));
$output = new BufferedOutput();
$application = new Application();
$application->run($input, $output);
dd($output->fetch());
Things i would like to achieve:
Download/Update individual packages
Get result output to verify success
Dump autoload
Remove/require packages
A bit of context details:
I am creating a plugin updater for my PHP application (in admin panel).
Every plugin is a composer package and resides on my own Satis repository.
The plugins get installed into a custom dir using my composer plugin.
I can read composer.lock locally and packages.json on the satis server to figure out
what packages require updates.
update
I've managed to at least get it to work. The no-output issue was due to $application->setAutoExit that needed to be false before running. Next issue that i had was that the required package would download itself into the same directory as the class where i called it from. Solved that by using putenv and chdir. Result:
root/comp.php
putenv('COMPOSER_HOME=' . __DIR__ . '/vendor/bin/composer');
chdir(__DIR__);
root/workbench/sumvend/sumpack/src/PackageManager.php
include(base_path() . '/comp.php');
$input = new ArrayInput(array('command' => 'require', 'packages' => ['vend/pak dev-master']));
$output = new BufferedOutput();
$application = new Application();
$application->setAutoExit(false);
$application->run($input, $output); //, $output);
dd($output->fetch());
This works, but it's far from ideal.
The full solution to this would be pretty long winded, but I will try to get you on the right track.
php composer.phar require composer/composer dev-master
You can load the source of composer into your project vendors. You might have already done this.
The code you are looking for is at: Composer\Command\RequireCommand.
$install = Installer::create($io, $composer);
$install
->setVerbose($input->getOption('verbose'))
->setPreferSource($input->getOption('prefer-source'))
->setPreferDist($input->getOption('prefer-dist'))
->setDevMode($updateDevMode)
->setUpdate(true)
->setUpdateWhitelist(array_keys($requirements))
->setWhitelistDependencies($input->getOption('update-with-dependencies'));
;
$status = $install->run();
Most of the command relates to the reading and writing to of the composer.json file.
However the installer itself is independent of where the configuration actually came from. You could in theory store the configuration in a database.
This is the static create method for the installer:
public static function create(IOInterface $io, Composer $composer)
{
return new static(
$io,
$composer->getConfig(),
$composer->getPackage(),
$composer->getDownloadManager(),
$composer->getRepositoryManager(),
$composer->getLocker(),
$composer->getInstallationManager(),
$composer->getEventDispatcher(),
$composer->getAutoloadGenerator()
);
}
You will need to pay special attention to the Package, And implement your own.
Although your current attempt to run it on the command line will work, I do not recommend it because Composer is primarily a development and deployment utility, not an application utility.
In order to smoothly use it to assist with loading plugins on a production environment, you will need to tightly integrate its internals with your own application, not just use it on the side.
This is something I am interested in as well, and I think this has inspired me to look into it myself. So I'll let you know what I come up with, but this is the best I can advise you for now on what I consider to be the correct approach.

How reload Twig cache in Symfony 2

I have a application which is developed in PHP using the Symfony 2 framework. I have changed a HTML file, but the change is not reflecting when I refresh the page.
I restarted the server. No luck.
I tried to remove the Twig folder from the /protected/cache/ page itself. This is not loading.
How can I reload the Twig cache?
Notes:
I am using tomcat server to deploy.
I don’t have the Symfony 2 command line configured on the server.
I am new to PHP.
The most simple way, type the command :
rm -rf app/cache/*
The point is: all files in app/cache/ can be removed freely, they are regenerated when needed.
If you really want to clear only twig cache :
rm -rf app/cache/<environment>/twig
Replace <environment> by dev, prod, or test according to your requirements.
When creating a new Twig_Environment instance, you can pass an array of options as the constructor second argument. One of them is auto_reload. When developing with Twig, it's useful to recompile the template whenever the source code changes. If you don't provide a value for the auto_reload option, it will be determined automatically based on the debug value.
Set auto_reload to be true:
$twig = new Twig_Environment($loader, array('auto_reload' => true));
Twig's documentation for developers:
http://twig.sensiolabs.org/doc/api.html#environment-options
I had a similar problem, but deleting the cache-folder did not have any impact on my template and I don't know why. What seems to solve my problem now is the following code in my config_dev.yml:
twig:
cache: false
Maybe this is also a solution for you, so that you don't need to use the command all the time.
References:
TwigBundle Configuration
Twig Environment Options
If you are using opcache/other similar caching, deleting twig's cache folder won't refresh templates as twig cache consist of only .php files.
You need to delete twig's cache folder + execute php file which contains:
opcache_reset();
You have to do some changes in app.php file located in web folder.
Change:
$kernel = new AppKernel('prod', false);
to:
$kernel = new AppKernel('prod', true);
and clear the cache if you want.
You can use the Symfony console to clear cache
./bin/console cache:clear
you can add a function like this :
public function renderView($view, array $parameters = array())
{
$loader = new \Twig_Loader_Filesystem($this->container->getParameter("template_path"));
$twig = new \Twig_Environment($loader, array('auto_reload' => true,
'cache' => false
));
/////////////////////add a translate filter///////////////////////
$getTextdomain = new \Twig_SimpleFilter('trans',function ($string){
return $this->container->get('translator')->trans($string);
});
$twig->addFilter($getTextdomain);
//////////////////////////////////////////////////////////////////
///////////////////////////Add an extension twig//////////////////
$twig->addExtension(new Extension());
//////////////////////////////////////////////////////////////////
return $twig->render($view, $parameters);
}
If you are using OPcache make sure to comment out opcache.validate_timestamps=0 in dev environment.

How to clear APC cache entries?

I need to clear all APC cache entries when I deploy a new version of the site.
APC.php has a button for clearing all opcode caches, but I don't see buttons for clearing all User Entries, or all System Entries, or all Per-Directory Entries.
Is it possible to clear all cache entries via the command-line, or some other way?
You can use the PHP function apc_clear_cache.
Calling apc_clear_cache() will clear the system cache and calling apc_clear_cache('user') will clear the user cache.
I don't believe any of these answers actually work for clearing the APC cache from the command line. As Frank Farmer commented above, the CLI runs in a process separate from Apache.
My solution for clearing from the command line was to write a script that copies an APC clearing script to the web directory and accesses it and then deletes it. The script is restricted to being accessed from the localhost.
apc_clear.php
This is the file that the script copies to the web directory, accesses, and deletes.
<?php
if (in_array(#$_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1')))
{
apc_clear_cache();
apc_clear_cache('user');
apc_clear_cache('opcode');
echo json_encode(array('success' => true));
}
else
{
die('SUPER TOP SECRET');
}
Cache clearing script
This script copies apc_clear.php to the web directory, accesses it, then deletes it. This is based off of a Symfony task. In the Symfony version, calls are made to the Symfony form of copy and unlink, which handle errors. You may want to add checks that they succeed.
copy($apcPaths['data'], $apcPaths['web']); //'data' is a non web accessable directory
$url = 'http://localhost/apc_clear.php'; //use domain name as necessary
$result = json_decode(file_get_contents($url));
if (isset($result['success']) && $result['success'])
{
//handle success
}
else
{
//handle failure
}
unlink($apcPaths['web']);
I know it's not for everyone but: why not to do a graceful Apache restart?
For e.g. in case of Centos/RedHat Linux:
sudo service httpd graceful
Ubuntu:
sudo service apache2 graceful
This is not stated in the documentation, but to clear the opcode cache you must do:
apc_clear_cache('opcode');
EDIT: This seems to only apply to some older versions of APC..
No matter what version you are using you can't clear mod_php or fastcgi APC cache from a php cli script since the cli script will run from a different process as mod_php or fastcgi. You must call apc_clear_cache() from within the process (or child process) which you want to clear the cache for. Using curl to run a simple php script is one such approach.
If you are running on an NGINX / PHP-FPM stack, your best bet is to probably just reload php-fpm
service php-fpm reload (or whatever your reload command may be on your system)
If you want to clear apc cache in command : (use sudo if you need it)
APCu
php -r "apcu_clear_cache();"
APC
php -r "apc_clear_cache(); apc_clear_cache('user'); apc_clear_cache('opcode');"
Another possibility for command-line usage, not yet mentioned, is to use curl.
This doesn't solve your problem for all cache entries if you're using the stock apc.php script, but it could call an adapted script or another one you've put in place.
This clears the opcode cache:
curl --user apc:$PASSWORD "http://www.example.com/apc.php?CC=1&OB=1&`date +%s`"
Change the OB parameter to 3 to clear the user cache:
curl --user apc:$PASSWORD "http://www.example.com/apc.php?CC=1&OB=3&`date +%s`"
Put both lines in a script and call it with $PASSWORD in your env.
apc_clear_cache() only works on the same php SAPI that you want you cache cleared. If you have PHP-FPM and want to clear apc cache, you have do do it through one of php scripts, NOT the command line, because the two caches are separated.
I have written CacheTool, a command line tool that solves exactly this problem and with one command you can clear your PHP-FPM APC cache from the commandline (it connects to php-fpm for you, and executes apc functions)
It also works for opcache.
See how it works here: http://gordalina.github.io/cachetool/
As defined in APC Document:
To clear the cache run:
php -r 'function_exists("apc_clear_cache") ? apc_clear_cache() : null;'
If you want to monitor the results via json, you can use this kind of script:
<?php
$result1 = apc_clear_cache();
$result2 = apc_clear_cache('user');
$result3 = apc_clear_cache('opcode');
$infos = apc_cache_info();
$infos['apc_clear_cache'] = $result1;
$infos["apc_clear_cache('user')"] = $result2;
$infos["apc_clear_cache('opcode')"] = $result3;
$infos["success"] = $result1 && $result2 && $result3;
header('Content-type: application/json');
echo json_encode($infos);
As mentioned in other answers, this script will have to be called via http or curl and you will have to be secured if it is exposed in the web root of your application. (by ip, token...)
if you run fpm under ubuntu, need to run the code below (checked on 12 and 14)
service php5-fpm reload
The stable of APC is having option to clear a cache in its interface itself. To clear those entries you must login to apc interface.
APC is having option to set username and password in apc.php file.
apc.ini
apc.stat = "1" will force APC to stat (check) the script on each request to determine if it has been modified. If it has been modified it will recompile and cache the new version.
If this setting is off, APC will not check, which usually means that to force APC to recheck files, the web server will have to be restarted or the cache will have to be manually cleared. Note that FastCGI web server configurations may not clear the cache on restart. On a production server where the script files rarely change, a significant performance boost can be achieved by disabled stats.
New APC Admin interface have options to add/clear user cache and opcode cache, One interesting functionality is to add/refresh/delete directory's from opCode Cache
APC Admin Documentation
A good solution for me was to simply not using the outdated user cache any more after deploy.
If you add prefix to each of you keys you can change the prefix on changing the data structure of cache entries. This will help you to get the following behavior on deploy:
Don't use outdated cache entries after deploy of only updated structures
Don't clean the whole cache on deploy to not slow down your page
Some old cached entries can be reused after reverting your deploy (If the entries wasn't automatically removed already)
APC will remove old cache entries after expire OR on missing cache space
This is possible for user cache only.
Create APC.php file
foreach(array('user','opcode','') as $v ){
apc_clear_cache($v);
}
Run it from your browser.
My work-around for Symfony build having loot of instances at the same server:
Step 1.
Create trigger or something to set a file flag (eg. Symfony command) then create marker file ..
file_put_contents('clearAPCU','yes sir i can buggy')
Step 2.
On index file at start add clearing code and remove marker file.
if(file_exists('clearAPCU')){
apcu_clear_cache();
unlink('clearAPCU');
}
Step 2.
Run app.
TL;DR: delete cache files at /storage/framework/cache/data/
I enabled APC but it wasn't installed (and also couldn't be installed), so it threw Call to undefined function Illuminate\Cache\apc_store().
"Ok, I'd just disable it and it should work".
Well, nope. Then I got stuck with Call to undefined function Illuminate\Cache\apc_delete()
We had a problem with APC and symlinks to symlinks to files -- it seems to ignore changes in files itself. Somehow performing touch on the file itself helped. I can not tell what's the difference between modifing a file and touching it, but somehow it was necessary...

Force re-cache of WSDL in php

I know how to disable WSDL-cache in PHP, but what about force a re-caching of the WSDL?
This is what i tried: I run my code with caching set to disabled, and the new methods showed up as espected. Then I activated caching, but of some reason my old non-working wsdl showed up again. So: how can I force my new WSDL to overwrite my old cache?
I guess when you disable caching it will also stop writing to the cache. So when you re-enable the cache the old cached copy will still be there and valid. You could try (with caching enabled)
ini_set('soap.wsdl_cache_ttl', 1);
I put in a time-to-live of one second in because I think if you put zero in it will disable the cache entirely but not remove the entry. You probably will only want to put that line in when you want to kill the cached copy.
In my php.ini there's an entry which looks like this:
soap.wsdl_cache_dir="/tmp"
In /tmp, I found a bunch of files named wsdl-[some hexadecimal string]
I can flush the cached wsdl files with this command:
rm /tmp/wsdl-*
Delete the old WSDL from the cache.
I'd try
$limit = ini_get('soap.wsdl_cache_limit');
ini_set('soap.wsdl_cache_limit', 0);
ini_set('soap.wsdl_cache_limit', $limit);
Or possibly set soap.wsdl_cache_ttl to 0 and back

Categories