I would like to know why when I clone my ZF2 project to a local machine to do some testing it completly stops working.
In my local machine I have two subfolders, one with a cakePHP project and the other with the ZF2 I've cloned.
The cakePHP project is working fine since it was there first, but the ZF2, when I try to access to the public folder it prints me:
{"error":"Something went wrong"}
A really generic error... I have no clue about what is going on.
I've tried some general debug attemps like
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
with no success at all, I've also checked the .htaccess RewriteBase directive to match my subfolder and the DB configuration is done too.
I have researched a bit in the project and the file which displays the error is module/RestfulV2_2/Module.php (Reading the README.md I've discovered is part of ZF2 Restful Module Skeleton):
/**
* #param MvcEvent $e
* #return null|\Zend\Http\PhpEnvironment\Response
*/
public function errorProcess(MvcEvent $e)
{
/** #var \Zend\Di\Di $di */
$di = $e->getApplication()->getServiceManager()->get('di');
$eventParams = $e->getParams();
/** #var array $configuration */
$configuration = $e->getApplication()->getConfig();
$vars = array();
if (isset($eventParams['exception'])) {
/** #var \Exception $exception */
$exception = $eventParams['exception'];
if ($configuration['errors']['show_exceptions']['message']) {
$vars['error-message'] = $exception->getMessage();
}
if ($configuration['errors']['show_exceptions']['trace']) {
$vars['error-trace'] = $exception->getTrace();
}
}
if (empty($vars)) {
$vars['error'] = 'Something went wrong';
}
/** #var PostProcessor\AbstractPostProcessor $postProcessor */
$postProcessor = $di->get(
$configuration['errors']['post_processor'],
array('vars' => $vars, 'response' => $e->getResponse())
);
$postProcessor->process();
if (
$eventParams['error'] === \Zend\Mvc\Application::ERROR_CONTROLLER_NOT_FOUND ||
$eventParams['error'] === \Zend\Mvc\Application::ERROR_ROUTER_NO_MATCH
) {
$e->getResponse()->setStatusCode(\Zend\Http\PhpEnvironment\Response::STATUS_CODE_501);
} else {
$e->getResponse()->setStatusCode(\Zend\Http\PhpEnvironment\Response::STATUS_CODE_500);
}
$e->stopPropagation();
return $postProcessor->getResponse();
}
The line which is calling the error in my index.php is:
Zend\Mvc\Application::init(require 'config/application.config.php')- run();
And the only line I found where the error function is called some way is this one in my modele.php :
$sharedEvents->attach('Zend\Mvc\Application', MvcEvent::EVENT_DISPATCH_ERROR, array($this, 'errorProcess'), 999);
Can you help me to solve this? I'm inexperienced with ZF2 but I know that with cakePHP to make it work you need to clear the cache folder. Is there any similar process in ZF2? Should I virtualize two servers to avoid conflics?
Thank you in advance.
EDIT : I've already made virtual hosts to avoid any possible conflict between my two frameworks but the error output is still the same.
EDIT2 : Here is my application.config.php file:
return array(
// This should be an array of module namespaces used in the application.
'modules' => array(
'Restful',
'MvlabsSnappy',
'Qrcode',
'Application',
'RestfulV2',
'RestfulV2_2'
),
// These are various options for the listeners attached to the ModuleManager
'module_listener_options' => array(
// This should be an array of paths in which modules reside.
// If a string key is provided, the listener will consider that a module
// namespace, the value of that key the specific path to that module's
// Module class.
'module_paths' => array(
'./module',
'./vendor',
),
// An array of paths from which to glob configuration files after
// modules are loaded. These effectively override configuration
// provided by modules themselves. Paths may use GLOB_BRACE notation.
'config_glob_paths' => array(
'config/autoload/{,*.}{global,local}.php',
),
// Whether or not to enable a configuration cache.
// If enabled, the merged configuration will be cached and used in
// subsequent requests.
//'config_cache_enabled' => $booleanValue,
// The key used to create the configuration cache file name.
//'config_cache_key' => $stringKey,
// Whether or not to enable a module class map cache.
// If enabled, creates a module class map cache which will be used
// by in future requests, to reduce the autoloading process.
//'module_map_cache_enabled' => $booleanValue,
// The key used to create the class map cache file name.
//'module_map_cache_key' => $stringKey,
// The path in which to cache merged configuration.
//'cache_dir' => $stringPath,
// Whether or not to enable modules dependency checking.
// Enabled by default, prevents usage of modules that depend on other modules
// that weren't loaded.
// 'check_dependencies' => true,
),
// Used to create an own service manager. May contain one or more child arrays.
//'service_listener_options' => array(
// array(
// 'service_manager' => $stringServiceManagerName,
// 'config_key' => $stringConfigKey,
// 'interface' => $stringOptionalInterface,
// 'method' => $stringRequiredMethodName,
// ),
// )
// Initial configuration with which to seed the ServiceManager.
// Should be compatible with Zend\ServiceManager\Config.
// 'service_manager' => array(),
);
First I would open index.php or whatever used as initial file (DirectoryIndex) and temporarily completely replace whole its content with something very base and simple, for example just these two lines:
<?php
phpinfo();
And then make sure that it started to work after that - with that simple code which just displays your php configuration. So we'll find out that there is no error in server configurations, permissions and etc. and nothing prevents your script from run.
Then I would do the same at your old project location just to get phpinfo() from that place too and waste some time trying to compare them. Maybe you missed something important and you'll now see it.
If no - next step I would check your DB connectivity if your project uses any DB... also with some very simple commands like connect, bind, ....
And finally I'd try to restore original project content step by step from its begin, and look at which step it will fail. It doesn't matter that there maybe no any output - you may put echo __LINE__ . ' works!<br/>'; between blocks, so your index.php will look like:
<?php
// original code block 1
echo __LINE__ . ' works!<br/>';
// original code block 2
echo __LINE__ . ' works!<br/>';
And you'll see in browser where it fails.
This is a very base description of my debug principals, but hope it will help.
The error could be anything. However, assuming the posted code is executed, it will suppress an error message without the correct configuration.
Try adding the following config to local.config.php.
return [
'errors'=> [
'show_exceptions' => [
'message' => true,
'trace' => true
],
],
];
If an exception is being thrown and that listener is catching it, then the $eventParams is something you should debug.
Related
I'm new at static analysis and I'm trying to use phan/phan on my current project.
My phan/config.php is as follow.
<?php
/**
* This configuration will be read and overlaid on top of the
* default configuration. Command-line arguments will be applied
* after this file is read.
*/
return [
// Supported values: `'5.6'`, `'7.0'`, `'7.1'`, `'7.2'`, `'7.3'`,
// `'7.4'`, `null`.
// If this is set to `null`,
// then Phan assumes the PHP version which is closest to the minor version
// of the php executable used to execute Phan.
//
// Note that the **only** effect of choosing `'5.6'` is to infer
// that functions removed in php 7.0 exist.
// (See `backward_compatibility_checks` for additional options)
// TODO: Set this.
'target_php_version' => null,
// A list of directories that should be parsed for class and
// method information. After excluding the directories
// defined in exclude_analysis_directory_list, the remaining
// files will be statically analyzed for errors.
//
// Thus, both first-party and third-party code being used by
// your application should be included in this list.
'directory_list' => [
'src',
'vendor/symfony/console',
],
// A regex used to match every file name that you want to
// exclude from parsing. Actual value will exclude every
// "test", "tests", "Test" and "Tests" folders found in
// "vendor/" directory.
'exclude_file_regex' => '#^vendor/.*/(tests?|Tests?)/#',
// A directory list that defines files that will be excluded
// from static analysis, but whose class and method
// information should be included.
//
// Generally, you'll want to include the directories for
// third-party code (such as "vendor/") in this list.
//
// n.b.: If you'd like to parse but not analyze 3rd
// party code, directories containing that code
// should be added to both the `directory_list`
// and `exclude_analysis_directory_list` arrays.
'exclude_analysis_directory_list' => [
'vendor/'
],
];
?>
My problem is that I have a lot of "false positive" errors like this :
src\Controller\UserController.php:6 PhanUnreferencedUseNormal Possibly zero references to use statement for classlike/namespace Route (\Symfony\Component\Routing\Annotation\Route)
src\Controller\UserController.php:7 PhanUnreferencedUseNormal Possibly zero references to use statement for classlike/namespace UserPasswordEncoderInterface (\Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface)
src\Controller\UserController.php:8 PhanUnreferencedUseNormal Possibly zero references to use statement for classlike/namespace ContainerBagInterface (\Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface)
src\Controller\UserController.php:9 PhanUnreferencedUseNormal Possibly zero references to use statement for classlike/namespace Security (\Sensio\Bundle\FrameworkExtraBundle\Configuration\Security)
It seems that phan can't detect Symfony vendors and I'm wondering how to correct it ?
I'm using php 7.4 with a Symfony 5 project
Looks like it's known issue:
https://github.com/phan/phan/issues/1757
In this Github issue, they advise using Phan Extension: https://github.com/Drenso/PhanExtensions#annotationsymfonyannotationplugin
Or try using PHPStan or Psalm.
I found it, the problem was on the following lines :
'directory_list' => [
'src',
'vendor/symfony/console',
],
This was taken directly from Phan example configuration, but since only the folder 'vendor/symfony/console' is included in directory_list, Phan has no way to know other Symfony components.
I've replaced this with :
'directory_list' => [
'src',
'vendor',
],
By including the entire vendor directory, it is parsed and Phan know every vendor object used in src.
As mentionned by Leprechaun, I've encoutered another problem with annotation not being correctly parsed by phan, and had to include the following plugin
'plugins' => [
'vendor/drenso/phan-extensions/Plugin/Annotation/SymfonyAnnotationPlugin.php'
],
Now it works.
I'm wondering what is the best way to inject dynamic configuration(retrieved from db for instance) into configuration array in Zend Framework 2? In Module.php I have:
public function onBootstrap(MvcEvent $e) {
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
$eventManager->attach('route', array($this, 'mergeDynamicConfig'));
}
public function mergeDynamicConfig(EventInterface $e) {
$application = $e->getApplication();
$sm = $application->getServiceManager();
$configurationTable = $sm->get('DynamicConfiguration\Model\Table\ConfigurationTable');
$dynamicConfig = $configurationTable->fetchAllConfig();
//Configuration array from db
//Array
//(
// [config] => 'Test1',
// [config2] => 'Test2',
// [config3] => 'Test3',
//)
//What to do here?
//I want to use the configurations above like $sm->get('Config')['dynamic_config']['config3'];
}
There is a section in the documentation that explains how to manipulate the merged configuration using the specific event ModuleEvent::EVENT_MERGE_CONFIG
Zend\ModuleManager\Listener\ConfigListener triggers a special event, Zend\ModuleManager\ModuleEvent::EVENT_MERGE_CONFIG, after merging all configuration, but prior to it being passed to the ServiceManager. By listening to this event, you can inspect the merged configuration and manipulate it.
The problem with this is that the service manager is not available at this point as the listener's event is one of the first events triggered by the module manager at priority 1000).
This means that you cannot execute your query and merge the config prior to the configuration being passed to the service manager, you would need to do so after.
Perhaps I have misunderstood your requirements, however I would approach this differently.
You could replace any calls where you need config $serviceManager->get('config') with $serviceManager->get('MyApplicationConfig'); which would be you own configuration service that uses the merged application config and then adds to it.
For example, you could register this configuration service in module.config.php.
return [
'service_manager' => [
'factories' => [
'MyApplicationConfig' => 'MyApplicationConfig\Factory\MyApplicationConfigFactory',
]
],
];
And create a factory to do the loading of merged module configuration, making any database calls or caching etc.
class MyApplicationConfigFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $sm)
{
$config = $sm->get('config');
$dbConfig = $this->getDatabaseConfigAsArray($sm);
return array_replace_recursive($config, $dbConfig);
}
protected function getDatabaseConfigAsArray(ServiceLocatorInterface $sm)
{}
}
You also have the added benefit that the service is lazy loaded.
I would not use this approuch, for a few reasons.
Putting SQL queries in your Module.php means that they will get executed on EVERY request for every user thus making your application slow, very slow.
If your database is compromised all the config will be stolen as well.
Solution would be to move all the config in your config/autoload/my_custom_config.local.php via array with keys. From there you can always load it without making a single database request. It will be way faster and secure, because the file will be outside your root folder and hacking a server is always alot harder than hacking a database.
If you still want to allow users to eit the options you can simply include the file in an action and show it with a foreach for example. To save the information you can do this:
file_put_contents("my_custom_config.local.php", '<?php return ' . var_export($config, true).';');
One other plus is that if you load your config the way discribe above you can also retrive the config like you want via $sm->get('Config')['dynamic_config']['config3']
In my project I use code below to add to assetic some named assets and one of them use lessphp filter.
public function prepend(ContainerBuilder $container)
{
$configs = $container->getExtensionConfig($this->getAlias());
$config = $this->processConfiguration(new Configuration(), $configs);
$this->configureAsseticBundle($container, $config);
}
protected function configureAsseticBundle(ContainerBuilder $container, array $config)
{
foreach (array_keys($container->getExtensions()) as $name) {
switch ($name) {
case 'assetic':
$container->prependExtensionConfig(
$name,
array(
'assets' => array(
'some_less' => array(
'inputs' => array(
'#SomeBundle/Resources/public/less/some.less'
),
'filters' => array('lessphp'),
),
)
)
);
break;
}
}
}
When I dump assets using assetic:dump everything is working fine in production enviroment but in dev enviroment lessphp filter for this named asset works only after few page refresh and after some time it doesn't work anymore and I need to remove all cache. After remove cache it work fine again... for few minutes...
I also noticed that it stop working when I edit any bundle extension class (DependencyInjection/[BundleName]Extension.php).
Does anyone have any idea what i did wrong?
I suspect this is because of the issue reported here. There's a bug in the Assetic code that will incorrectly "clear" out the filters for an asset during rendering, so they are never applied.
You should be able to reliably reproduce it by clearing the cache with php app/console cache:clear. But you should then be able to "fix" it by completely removing the dev cache files and reloading the page.
The PR I referenced is not get committed (it's waiting for a test), but it's a couple lines of a code you can manually add just to confirm it's the fix you're looking for.
I'm using file caching (CFileCache) to show a simple message from a database table.
When page load for the first time it works correct but when I reload page it makes an Error as:
include(CTimestampBehavior.php) [function.include]: failed to open stream: No such file or directory
And This error remains until TIME EXPIRATION which I set in cache->set() and next page load just one time and it makes error again and so on.
Here is my method to handle caching:
public static function getLatest()
{
//see if it is in the cache, if so, just return it
if( ($cache=Yii::app()->cache)!==null)
{
$key='TrackStar.ProjectListing.SystemMessage';
if(($sysMessage=$cache->get($key))!==false)
return $sysMessage;
}
//The system message was either not found in the cache, or
//there is no cache component defined for the application
//retrieve the system message from the database
$sysMessage = SysMessage::model()->find(array(
'order'=>'t.update_time DESC',
));
if($sysMessage != null)
{
//a valid message was found. Store it in cache for future retrievals
if(isset($key))
//$cache->set($key,$sysMessage,300);
$cache->set($key, $sysMessage, 300, new CDbCacheDependency('SELECT MAX(update_time) FROM tbl_sys_message'));
return $sysMessage;
}
else
return null;
}
Error occures in this line:
if(($sysMessage=$cache->get($key))!==false)
I'm new to Yii and caching and have no idea about it.
UPDATE:
behaviors method of AR models:
public function behaviors()
{
return array(
'CTimestampBehavior' => array(
'class' => 'zii.behaviors.CTimestampBehavior',
'createAttribute' => 'create_time',
'updateAttribute' => 'update_time',
'setUpdateOnCreate' => true,
),
);
}
This looks like your issue is either that:
framework/zii/behaviors/CTimestampBehavior.php is missing
framework/zii/behaviors/CTimestampBehavior.php doesn't have correct permissions to be read by your server user
You are using opcode cache (APC?) and there are some issues on that end, (though reports for this seem to be for random occurrences). Try disabling it.
For some unknown reason Yii doesn't import your zii routes
In any event I suggest trying a workaround of adding "zii.behaviors.CTimestampBehavior" to your main.php configuration file "import" section. Or simply calling Yii::import('zii.behaviors.CTimestampBehavior'); in your function. Hopefully that works and you can continue with your work while diving deaper into the issue when you've got the time.
If it doesn't you can investigate the above (and at least people who come here will have more information to work with)
What is the best way to go about getting sessions up and running in Zend Framework 2? I've tried setting session_start() in my index.php file but then that gets run before any autoloaders have been bootstrapped, leading to incomplete objects sitting in my sessions.
In ZF1 you could have it initialize sessions by adding some options into the config, but I'm at a loss on how to do this in ZF2.
If i understand you correctly, all you wanna do is have your session working properly in your modules? Assuming that's correct there are two single steps.
1) Create the config: module.config.php
return array(
'session' => array(
'remember_me_seconds' => 2419200,
'use_cookies' => true,
'cookie_httponly' => true,
),
);
2) Start your Session: Module.php
use Zend\Session\Config\SessionConfig;
use Zend\Session\SessionManager;
use Zend\Session\Container;
use Zend\EventManager\EventInterface;
public function onBootstrap(EventInterface $evm)
{
$config = $evm->getApplication()
->getServiceManager()
->get('Configuration');
$sessionConfig = new SessionConfig();
$sessionConfig->setOptions($config['session']);
$sessionManager = new SessionManager($sessionConfig);
$sessionManager->start();
/**
* Optional: If you later want to use namespaces, you can already store the
* Manager in the shared (static) Container (=namespace) field
*/
Container::setDefaultManager($sessionManager);
}
Find more options in the documentation of \Zend\Session\Config\SessionConfig
If you want to store cookies too, then please see this Question. Credits to Andreas Linden for his initial answer - I'm simply copy pasting his.