Oxidshop - Override changebasket function in BasketComponent - php

I am customising Oxidshop for one of my clients. I want to customise the "changebasket" function in BasketComponent file to add more validations to it.
For this purpose I have also created a custom module. I am trying to extend the class using metadata file.
'extend' => array(
'oxcmp_basket' => \MyVendor\Basket\Application\Components\BasketComponent::class,
),
The BasketComponent file has following code,
<?php
namespace MyVendor\Basket\Application\Components;
/**
* Class LinslinSliderMain.
*/
class BasketComponent extends BasketComponent_parent
{
/**
* #param null $sProductId
* #param null $dAmount
* #param null $aSel
* #param null $aPersParam
* #param bool $blOverride
*/
public function changebasket($sProductId = null, $dAmount = null, $aSel = null, $aPersParam = null, $blOverride = true)
{
echo 'call success';exit;
parent::changebasket($sProductId, $dAmount, $aSel, $aPersParam, $blOverride);
}
}
The gets activated. However, when I refresh any page in frontend, it gets deactivated automatically. I don't know, what's wrong with the code.
EDIT: I am getting this error in oxideshop.log file
Module class MyVendor\Basket\Application\Components\BauerBasketComponent not found. Module ID basket disabled.

depending on your OXID eShop version it might be a different line, but the error message you are stating originates from OxidEsales\EshopCommunity\Core\Module\ModuleChainsGenerator::onModuleExtensionCreationError.
When activating your module, the system tries to generate the class chain with your BasketComponent class in it. As your class is a namespaced class, OXID tries to check if it can find the class via the composer autoload file, if not, the shop throws this exception.
So I assume the module is not installed via composer, at least the namespace seems unknown to composer. You can check in the module documentation on how this should be achieved
Hope I could help
/Flo

Related

How to import and register class from a list of service providers at runtime?

Are you able to solve this problem? help me
Procedure
There is a folder called 'plugins' in the base path of laravel;
Inside that folder there are only subfolders that are the plugins;
In the subfolder where the plugin is, there is a single file to be imported called PluginNameServiceProvider.php;
The PluginNameServiceProvider.php in turn will be registered by a main service provider, let's say MainServiceProvider.php, but for that, the PluginNameServiceProvider class must be available/accessible for use;
Problem
The user loads the subfolder containing the 'plugin' in 'zip' format through a GUI, then the system extracts the loaded 'zip' file and directs it to the appropriate location, no similar file exists before that;
When the 'composer update or composer dump-autoload' command is executed the PluginNameServiceProvider class is resolved and can be used elsewhere, but not before that;
The aforementioned composer commands are executed at fixed times, however, the PluginNameServiceProvider class must be available immediately, not being able to depend on composer under penalty of preventing the use of the plugin;
What was tried
A temporary autoloader was created that searches for classes not yet resolved by composer as below, however, it is not working
try{
/**
* For information on 'spl_autoload_register' see: https://www.php.net/manual/en/function.spl-autoload-register.php
* For information on 'glob()' see: https://www.php.net/manual/en/function.glob.php
* For information on 'app()' see: https://laravel.com/docs/9.x/helpers#method-app
* base_path() returns the path of the plugins folder, something like: 'D:\www\laravel\plguins'
* $name returns the namespace of the plugin's service provider, something like: '\plugins\plugin-name\Providers\PluginNameServiceProvider'
* 'File::' is an abbreviation for the facade 'Illuminate\support\facades\File'
**/
//Import file if class not found
spl_autoload_register(function ($name) {
//Check if the file exists before importing it
if(File::exists(base_path($name). '.php')){
include(base_path($name). '.php');
}
});
//Access the plugins folder and list the directories
$folders = File::directories(base_path('plugins'));
//Iterates over a set of subfolders and accesses each one of them looking for a file with 'Provider.php' in the name
foreach($folders as $item){
//Returns the absolute path of the first service provider it finds
$str = collect(glob(base_path('plugins'). "\\". $item . '\\Providers\\*Provider.php'))->first();
//Proceed with registration if the plugin has a service provider, otherwise continue the loop
if(!is_null($str)){
//Prepare the class name and namespace to be used
$filter = pathinfo($str);
$path = $filter['dirname'] .'\\'. $filter['filename'];
$newclass = str_replace('.php', '', strstr($str, '\plugins'));
//Register the plugin provider
app()->register(new $newclass(app()));
}
}
} catch(\Exception $e){
dd($e->getMessage());
}
The problem with my code is that it is not registering the service providers whose namespace has not yet been mapped by the composer. The problem seems to be in spl_autoload_register, I say it seems because the code is in a place that 'kills' laravel in case of a fatal error so the debug options are minimal and the code cannot be moved to another place as it is included inside a package.
Current behavior
The service provider seems to have been imported due to the fact that 'include()' returns 1, however, there are two types of situations: 1) It gives the error 'class not found'; 2) It doesn't display any errors and it doesn't execute the service provider code either.
Expected behavior
The code must import the service provider and register it, so that the code present in that service provider is executed.
Plugin service provider example to be registered
<?php
namespace plugins\plugin-name\Providers;
use Illuminate\Support\ServiceProvider;
class PluginNameServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register()
{
dd(['status' => 'Registered!', 'more' => app()]);
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
}
I solved the problem with the modification below:
Before
//Returns the absolute path of the first service provider it finds
$str = collect(glob(base_path('plugins'). "\\". $item . '\\Providers\\*Provider.php'))->first();
After
//Returns the absolute path of the first service provider it finds
$str = collect(glob($item . '\\Providers\\*Provider.php'))->first();
I'll leave the code there in the question in case someone tries to implement a hook functionality in php and has a similar problem. If you use it, be kind and give proper credit.

Twig\Loader\FilesystemLoader not found when triggering 404 error

I'm new to OOP and MVC with PHP, and I'm currently learning by making my own custom MVC app for testing purposes. I’m not using Symfony yet, but I’ve integrated Twig and I have a problem with it when I call a 404 error outside a controller, in the two following cases :
When requested page doesn't exist on server (like http://localhost/test/)
When requested URL doesn't match with an existing controller and method (like http://localhost/test/task/)
I've got the following error :
Fatal error: Uncaught Error: Class 'Twig\Loader\FilesystemLoader' not found in /Applications/XAMPP/xamppfiles/htdocs/librairies/Renderer.php:32
Stack trace: #0 /Applications/XAMPP/xamppfiles/htdocs/librairies/Renderer.php(21): Renderer::loadTwig()
#1 /Applications/XAMPP/xamppfiles/htdocs/librairies/Http.php(26): Renderer::render('errors/404', Array)
#2 /Applications/XAMPP/xamppfiles/htdocs/librairies/Application.php(35): Http::error404()
#3 /Applications/XAMPP/xamppfiles/htdocs/index.php(9): Application::process()
#4 {main} thrown in /Applications/XAMPP/xamppfiles/htdocs/librairies/Renderer.php on line 32
However, if I call the right controller with an existing method, everything works fine (like http://localhost/article/show/123).
If I call 404 error inside a controller method (e.g. if the $_GET ID of an article does not exist in the DB), everything works fine too and my 404 error template is correctly rendered.
How I call a 404 error ?
I use a static method Http::error404() that render my 404 error Twig template.
class Http
{
/**
* Display a 404 error - page not found
*
* #return void
*/
public static function error404(): void
{
header('HTTP/1.1 404 Not Found');
$pageTitle = "Erreur 404 - Page non-trouvée";
Renderer::render('errors/404', compact('pageTitle'));
exit;
}
}
Application class
My App use a mini-router named Application. It checks if the controller and the called method exists. If not, call 404 error with Http::error404(), and it is in this case that the above fatal error appears.
class Application
{
/**
* This is the app process, called in index.php file.
* Use controllers and methods directly in URL.
* URL are rewritten by .htaccess file at app root.
*
* Usage : https://example.com/controller/task/{optional_parameter}
* Ex : https://example.com/article/show/145
*
* #return void
*/
public static function process()
{
// By default, call homepage
$controllerName = 'ArticleController';
$task = 'home';
if (!empty($_GET['controller'])) {
$controllerName = ucfirst($_GET['controller'] . 'controller');
}
if (!empty($_GET['task'])) {
$task = $_GET['task'];
}
$controllerPath = "\controllers\\" . $controllerName;
// Check if this controller & method exists
if (!method_exists($controllerPath, $task)) {
Http::error404(); // <-- Here, i'm not in a controller (line 35)
}
$controller = new $controllerPath();
$controller->$task();
}
}
There is a strange thing here : if I define any controller before calling 404 error, everything works as I would like and my 404 error template is correctly rendered. But it’s not a clean and elegant solution...
// Check if this controller & method exists
if (!method_exists($controllerPath, $task)) {
new \Controllers\ArticleController(); // <-- Not clean, but solve my fatal error
Http::error404();
}
The same thing happens in my 404.php file, called by the server and declared in the .htaccess when a file is called and it doesn’t exist. My 404 PHP file just contains few lines :
require_once 'librairies/autoload.php';
Http::error404();
If I define any controller, it's working perfectly and fatal error disappears.
require_once 'librairies/autoload.php';
new Controllers\ArticleController();
Http::error404();
Render Class
This is my rendering class. The fatal error appears in this file, as shown in line 32 below, when Http class with error404 method render errors/404 Twig template.
require_once 'librairies/autoload.php';
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
use Twig\TwigFunction;
class Renderer
{
/**
* Print a HTML template with $var injection
*
* #param string $path
* #param array $var
*/
public static function render(string $path, $var = [])
{
$template = self::loadTwig()->load("$path.html.twig");
echo $template->display($var);
}
/**
* Load Twig
*
* #return Environment
*/
public static function loadTwig()
{
$loader = new FilesystemLoader('templates'); // <-- Line 32 is here !
$twig = new Environment($loader, [
'auto_reload' => true,
'autoescape' => 'html'
]);
$twig->addFunction(
new TwigFunction('notificationDisplay', function() { return Notification::display(); })
);
return $twig;
}
}
I have only added the code that I think is related to my issue. Do not hesitate to ask if there are any points that need to be clarified.
I’ve been looking for a solution to this error for seven days and haven’t found a solution. Your help is my last resort. Thank you very much!
I removed all the many unnecessary require_once autoloader in app files, and kept only the one in index.php, as indicated by #NicoHaase.
From that point, Twig is no longer found and the same error message appears on all requests !
The solution was easy to find : in my index.php file, I was using the wrong autoloader. I was calling my custom autoloader instead of the one from Composer...
I just change :
require_once 'librairies/autoload.php';
\Application::process();
To :
require_once 'vendor/autoload.php';
\Application::process();
And everything works fine now ! Thanks to #NicoHaase and #DarkBee for putting me on the right track !

Fatal error: Cannot declare class MYCLASS Woocommerce Settings

I have a website, and when I go to the WordPress admin page and click on woocommerce-settings it shows this error:
Fatal error: Cannot declare class WC_Settings_General, because the
name is already in use in
/(hosting)/website/wp-content/plugins/woocommerce/includes/admin/settings/class-wc-settings-general.php
on line 0 The site is experiencing technical difficulties. Please
check your site admin email inbox for instructions.
The beginning of class-wc-settings-general.php looks like this:
<?php
/**
* WooCommerce General Settings
*
* #package WooCommerce/Admin
*/
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'WC_Settings_General', false ) ) {
return new WC_Settings_General();
}
/**
* WC_Admin_Settings_General.
*/
class WC_Settings_General extends WC_Settings_Page {
/**
* Constructor.
*/
public function __construct() {
$this->id = 'general';
$this->label = __( 'General', 'woocommerce' );
parent::__construct();
}
/**
* Get settings array.
*
* #return array
*/
public function get_settings() {
etc. The webpage url that is generating this error is: https://www.(mywebsite).com/wp-admin/admin.php?page=wc-settings
I need to know how to resolve this issue and get to the woocommerce settings. I have other websites that have woocommerce and do not have this issue, and I do not know where the other place it is declared would be.
If you need to know the list of plugins, please, let me know.
Please do not flag as a duplicate post as this is a very specific issue regarding woocommerce and WordPress that the other posts I have looked at (around 8 others) do not fix. I have checked for require to change to require_once
Thank you in advance!
I had exactly the same error, except it was pointing to line 0. I switched theme to Storefront and deactivated all plugins except WooCommerce, which fixed the problem... then switched the theme back and gradually added plugins back in to find out which was the problem.
Hopefully this can work for you as well - it was just a conflict with me on an old plugin I thankfully wasn't using any more anyway.

Logging Codeception Errors

I'm pretty new to Codeception and I have come across a problem I cannot figure out. I have about 40 tests in my test suite, and if a test fails, I need to send an email with the reason it failed. For example, if Codeception cannot find an element on the page resulting in a failed test, I need to send an email with just the error, like this:
Failed to verify emailing wish list behaves as expected in ThisClass::thisTest (/home/qauser/codeception_tests///acceptance-mobile/Wishlist/EmailWishlistCest.php)
Couldn't see "Success!","//*[#id="wish-list-confirm-popup"]/div/div/div[1]/h4":
I don't want to send the full stack trace, just the actual error. Does anyone know if this is possible?
Codeception exposes a useful collection of events that will come in handy for this use case. Take a look at the Customization: Events section of Codeception's documentation for more information.
I'd recommend intercepting two of the events described on that page:
The test.fail event, to aggregate information about each failed test.
The test.fail.print event, to process the aggregated data (eg. by sending a summary email) when Codeception has completed the test suite and prints its own summary of the failures to the screen.
To accomplish this, you simply need to build a custom event handler class and register it as an extension in the config file:
# codeception.yml
extensions:
enabled: [MyCustomEventHandler]
# MyCustomEventHandler.php
<?php
// Note: this was drafted using Codeception 2.0. Some of the namespaces
// maybe different if you're using a more-recent version of Codeception.
class MyCustomEventHandler extends \Codeception\Platform\Extension
{
/**
* #var \Exception[]
*/
protected $testFailures = [];
/**
* Maps Codeception events to method names in this class.
*
* Defining an event/method pair in this array essentially subscribes
* the method as a listener for its corresponding event.
*
* #var array
*/
public static $events = [
\Codeception\Events::TEST_FAIL => 'singleTestJustFailed',
\Codeception\Events::TEST_FAIL_PRINT => 'allTestFailuresAreBeingDisplayed',
];
/**
* This method will automatically be invoked by Codeception when a test fails.
*
* #param \Codeception\Event\FailEvent $event
*/
public function singleTestJustFailed(\Codeception\Event\FailEvent $event)
{
// Here we build a list of all the failures. They'll be consumed further downstream.
$this->testFailures[] = $event->getFail();
}
/**
* This method will automatically be invoked by Codeception when it displays
* a summary of all the test failures at the end of the test suite.
*/
public function allTestFailuresAreBeingDisplayed()
{
// Build the email.
$emailBody = '';
foreach ($this->testFailures as $failure) {
// Methods in scope include: $failure->getMessage(), $failure->getFile(), etc.
$emailBody .= $failure->getMessage() . "\r\n";
}
// Now send the email!
}
}
Hope this helps!

TYPO3 6.2: "Could not find a suitable type converter for "String" " exeption after update

TYPO3 was from a very old version updated to TYPO3 6.2. The most things are working now, but I have one own written extension that give me the following error:
Core: Exception handler (WEB): Uncaught TYPO3 Exception: #1297759968: Exception while property mapping at property path "":Could not find a suitable type converter for "String" because no such class or interface exists. | TYPO3\CMS\Extbase\Property\Exception thrown in file /srv/vhosts.d/typo3_src-6.2.9/typo3/sysext/extbase/Classes/Property/PropertyMapper.php in line 106.
I have a list Method in one of the controller that generates a link:
<f:link.action action="show" arguments="{id : course.id}"> {course.name}</f:link.action>
This list method works, but when I want to open this generated link in the website I get the error from above.
I delete all stuff in the showAction method and also change the template to a basic output without special things. The method looks than like this:
/**
* action show
*
* #param String Course-Id
* #return void
*/
public function showAction($id){
}
But the error is still there. I have absolutely no idea anymore what is the problem. It would be great when someone have a different view and properly have some ideas where I can try to find out what the problem really is.
I think it needs to be
/**
* action show
*
* #param string $id Course-Id
* #return void
*/
public function showAction($id){
}
string lowercase and the argument $id must be specified as well
I want to share my solution way:
The first problem was that I don't know that there is a new way to delete the cache of the core. That I find out because of Jost comment in my answer with the "clear the cache from install tool". So I go in the Backend of Typo3 to edit a user and edit there my own under Options the TSconfig field. I add there a row with options.clearCache.system = 1. Now I can clear the system core over the flash symbol in the Backend of Typo3.
After that I try to change the #param String in #param string. I deleted the core cache and then I got a different error. I found out that this new error say that only arrays or objects are as parameters are allowed in the action method (See: http://wiki.typo3.org/Exception/CMS/1253175643).
So I deleted the parameter and follow the instruction on the website where the error is explained. So my new method looks as follow:
/**
* action show
*
* #return void
*/
public function showAction(){
if ($this->request->hasArgument('id')) {
$id= $this->request->getArgument('id');
}
// Do stuff with the id
}
And that works now :)

Categories