Override Prestashop MyAccountController - overriding

I try to create override MyAccountController
class MyAccountController extends MyAccountControllerCore
{
public function init()
{
parent::init();
if ($module = Module::getInstanceByName('my_module')) {
$urls = $module->getData();
Tools::redirect($urls['redirect']);
}
}
}
I saved this file in override/controllers/front folder.
After some tests, it does not work. My redirection is not called.
But when I set to true the variable _PS_DEBUG_PROFILING_, the redirect is well captured by the profiler.
My Prestashop instance is clean. No modules or files are installed.
Prestashop version : 1.7.8.7

After place your controller in override, you need to rebuild the class index.
This is the file:
var/cache/prod/class_index.php
Just remove that file, it will be created again, taking in account your override.
Note: /prod/ because of production environment.

Related

Extend and override default lighthouse directive

Is there anyway that I can override a directive like: src/Schema/Directives/WhereDirective.php for instance this doesn't support some methods on my custom builder, I know I can make another directive and extend this like #myWhere but that's dirty, would be nice to be able to override the #where itself.
I've searched around but nothing was found about this sadly!
I edit my composer.json and manipulate the class mappings. In this example, I wanted to override some cache classes.
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/",
"Nuwave\\Lighthouse\\Cache\\": "lighthouseV6/cache/"
},
"exclude-from-classmap": [
"vendor/nuwave/lighthouse/src/Cache/CacheKeyAndTags.php",
"vendor/nuwave/lighthouse/src/Cache/CacheKeyAndTagsGenerator.php",
"vendor/nuwave/lighthouse/src/Cache/CacheDirective.php"
]
},
Then create a folder "lighthouseV6/cache" in the root of the project and copy the classes I wanted to override from "vendor/nuwave/lighthouse/src/Cache" inside it.
I found the solution. according to https://lighthouse-php.com/5/custom-directives/getting-started.html#register-directives
When Lighthouse encounters a directive within the schema, it starts looking for a matching class in the following order: 1. User-defined namespaces as configured in config/lighthouse.php, defaults to App\GraphQL\Directives 2. The RegisterDirectiveNamespaces event is dispatched to gather namespaces defined by plugins, extensions or other listeners 3. Lighthouse's built-in directive namespace.
So it did seem like override could be possible, and it was.
I haven't tried first method (App\GraphQL\Directive...) but that probably would work too, I went with the second method the RegisterDirectiveNamespaces event, since I was writing a package.
Make all your directives in the same folder under one namespace eg:
namespace SteveMoretz\Something\GraphQL\Directives;
Now in a service provider (Can be your package's service provider or AppServiceProvider or any service provider you get the idea.) register that namespace your directives are under.
use Illuminate\Contracts\Events\Dispatcher;
use Nuwave\Lighthouse\Events\RegisterDirectiveNamespaces;
class ScoutGraphQLServiceProvider {
public function register(Dispatcher $dispatcher) {
$dispatcher->listen(
RegisterDirectiveNamespaces::class,
static function (): string {
return "SteveMoretz\Something\GraphQL\Directives";
}
);
}
}
That's it so for an example I have overridden the #where directive, first I created a file named as original WhereDirective.php then put these contents in it:
<?php
namespace SteveMoretz\Something\GraphQL\Directives;
use Nuwave\Lighthouse\Scout\ScoutBuilderDirective;
use Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective;
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
use Nuwave\Lighthouse\Schema\Directives\WhereDirective as WhereDirectiveOriginal;
use Nuwave\Lighthouse\Support\Contracts\FieldResolver;
class WhereDirective extends WhereDirectiveOriginal
{
public function handleBuilder($builder, $value): object
{
$clause = $this->directiveArgValue('clause', 'where');
// do some other stuff too... my custom logic
return $builder->{$clause}(
$this->directiveArgValue('key', $this->nodeName()),
$this->directiveArgValue('operator', '='),
$value
);
}
}
Now whenever we use #where my custom directive runs instead of the original one, but be careful what you do in this directive don't alter the whole directive try to extend the original and add more options to it, otherwise you would end up confusing yourself later!

Install Symfony without symfony/runtime and with old index.php

I am trying to add Symfony 5.4 to my legacy project. There is a pretty nice documentation on how to do this, but there's a big problem - the documentation assumes "normal" Symfony, but each time I try to install Symfony using their recommended way of composer create-project, I get a Symfony version with symfony/runtime - the big problem here, is that this version has a completely different index.php:
<?php
use App\Kernel;
require_once dirname(_DIR_).'/vendor/autoload_runtime.php';
return function (array $context) {
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
};
The documentation found here is based on a completely different index file.
I did find that I can remove the runtime package, and just copy old index, and it works for the most part, but then you also have problems with console.php and I worry that if I go this route there will be more and more problems caused by my installation expecting symfony/runtime and me manually removing it's
I tried installing Symfony 5.3 as well as different patches of 5.4, all came with this installed, even though I did work on some 5.3 / 5.4 projects and had the old school index.php file.
Does anyone know how to currently install Symfony with the "old" index.php, console.php etc.?
Thanks!
So the task is to migrate from a non-Symfony legacy app to a Symfony app. The basic idea is to allow the Symfony app to process a request and then hand it off to the legacy app if necessary. The Symfony docs show how to do this but but relies on the older style index.php file. The newer runtime based approach is a bit different.
But in the end all it really takes is a couple of fairly simple classes. A runner class takes care of creating a request object and turning it into a response. This is where you can add the bridge to your legacy app. It's a clone of Symfony's HttpKernelRunner class:
namespace App\Legacy;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\TerminableInterface;
use Symfony\Component\Runtime\RunnerInterface;
class LegacyRunner implements RunnerInterface
{
private $kernel;
private $request;
public function __construct(HttpKernelInterface $kernel, Request $request)
{
$this->kernel = $kernel;
$this->request = $request;
}
public function run(): int
{
$response = $this->kernel->handle($this->request);
// check the response to see if it should be handed off to legacy app
dd('Response Code ' . $response->getStatusCode());
$response->send();
if ($this->kernel instanceof TerminableInterface) {
$this->kernel->terminate($this->request, $response);
}
return 0;
}
}
Next you need to wire up runner by extending the SymfonyRuntime::getRunner method:
namespace App\Legacy;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Runtime\RunnerInterface;
use Symfony\Component\Runtime\SymfonyRuntime;
class LegacyRuntime extends SymfonyRuntime
{
public function getRunner(?object $application): RunnerInterface
{
if ($application instanceof HttpKernelInterface) {
return new LegacyRunner($application, Request::createFromGlobals());
}
return parent::getRunner($application);
}
}
Finally, update composer.json to use your legacy runtime class:
"extra": {
...
"runtime": {
"class": "App\\Legacy\\LegacyRuntime"
}
}
After updating composer.json do a composer update for the changes to take effect and start your server. Navigate to a route and you should hit the dd statement.

symfony 3.1 Check if a bundle is installed

I'm developing a bundle who has a dependency on another one.
In order to handle the case that the base bundle has not been installed I'll like to perform a "bundle_exists()" function inside a controller.
The question is: How can I have a list of installed bundles or How can I check for the name (eventually also the version) of a bundle.
Thanks.
In addition to #Rooneyl's answer:
The best place to do such a check is inside your DI extension (e.g. AcmeDemoExtension). This is executed once the container is build and dumped to cache. There is no need to check such thing on each request (the container doesn't change while it's cached anyway), it'll only slow down your cache.
// ...
class AcmeDemoExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$bundles = $container->getParameter('bundles');
if (!isset($bundles['YourDependentBundle'])) {
throw new \InvalidArgumentException(
'The bundle ... needs to be registered in order to use AcmeDemoBundle.'
);
}
}
}
Your class needs to have access to the container object (either by extending or DI).
Then you can do;
$this->container->getParameter('kernel.bundles');
This will give you a list of bundles installed.
Update;
If you are in a controller that extends the Symfony\Bundle\FrameworkBundle\Controller\Controller or in a command class that extends Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand, you can just get the parameter.
$this->getParameter('kernel.bundles').
Else #Wouter J's answer is your best answer.
You can get a list of all Bundles from the Kernel like this:
public function indexAction ()
{
$arrBundles = $this->get("kernel")->getBundles();
if (!array_key_exists("MyBundle", $arrBundles))
{
// bundle not found
}
}
From Andrey at this question: How do I get a list of bundles in symfony2?
If you want to call a non static method of registered bundle object (not class) then you can do the following:
$kernel = $this->container->get('kernel');
$bundles = $kernel->getBundles();
$bundles['YourBundleName']->someMethod();
Where 'YourBundleName' is the name of your bundle, which you can get by calling from console:
php app/console config:dump-reference

Using StructureMap 3 in multiple ASP MVC projects

First lets start to describe my project architecture.
I have a asp.net mvc application called Portal.Web as startup project and multiple asp.net mvc applications which called Plugin.XXX (Plugin.News, Plugin.Cms, etc) and Portal.Web has references from all of these plugins.
I installed StrcutureMap.Mvc5 for each one of these Plugins
As you know, when you install StructureMap a folder created called DependencyResolution and it contains some files, one of them is IoC.cs where you can initialize your container.
Now my problem is since all plugins has their own IoC.cs, it seems like they override each other containers so at the end I get this error :
No parameterless constructor defined for this object
// inner exception
No default Instance is registered and cannot be automatically determined for type 'Portal.Plugins.Page.Interfaces.IPage'
There is no configuration specified for Portal.Plugins.Page.Interfaces.IPage
1.) new RouteController(*Default of IUnitOfWork*, *Default of IPage*)
2.) Portal.Web.Controllers.RouteController
3.) Instance of Portal.Web.Controllers.RouteController
4.) Container.GetInstance(Portal.Web.Controllers.RouteController)
There is no configuration specified for Portal.Plugins.Page.Interfaces.IPage
I could use ONE IoC.cs in Portal.Web project but I need to keep modularity and make Plugins independent as much as possible.
is there any way to keep plugins containers independent?
namespace Portal.Plugins.Account.DependencyResolution {
using StructureMap;
public static class IoC {
public static IContainer Initialize() {
return new Container(c =>
{
c.AddRegistry<DefaultRegistry>();
c.For<IUnitOfWork>().LifecycleIs(new HttpContextLifecycle()).Use<AccountDbContext>();
c.For<IAccount>().Use<AccountService>();
});
}
}
}
namespace Portal.Plugins.Cms.DependencyResolution {
using StructureMap;
public static class IoC {
public static IContainer Initialize() {
return new Container(c =>
{
c.AddRegistry<DefaultRegistry>();
c.For<IUnitOfWork>().LifecycleIs(new HttpContextLifecycle()).Use<CmsDbContext>();
c.For<IPage>().Use<PageService>();
c.For<IMenu>().Use<MenuService>();
c.For<IMedia>().Use<MediaService>();
});
}
}
}
If I understand your problem correctly, couldn't you create a DependencyResolution class library that contains the StructureMap.Mvc5 package that's then used throughout your plugins (this saves each of your plugins containing versions of StructureMap.Mvc5) and having a single reference to your DependencyResolution class library.
From here your individual plugins can then contain their own StructureMap registries, with more global registries being kept in the DependencyResolution class library.

PHPUnit inclusion path issues

This one's got me stumped. I've been working with PHPUnit for a couple of months now, so I'm not that green...but I look forward to being pointed in the direction of the obvious mistake I'm making! The initialisation process outlined below works fine if I run the "app" from a browser - but PHPUnit is choking...can any one put me out of my misery?
I'm trying to test a homebrew MVC, for study purposes. It follows a typical ZF layout.
Here's the index page:
include './../library/SKL/Application.php';
$SKL_Application = new SKL_Application();
$SKL_Application->initialise('./../application/configs/config.ini');
Here's the application class (early days...)
include 'bootstrap.php';
class SKL_Application {
/**
* initialises the application
*/
public function initialise($file) {
$this->processBootstrap();
//purely to test PHPUnit is working as expected
return true;
}
/**
* iterates over bootstrap class and executes
* all methods prefixed with "_init"
*/
private function processBootstrap() {
$Bootstrap = new Bootstrap();
$bootstrap_methods = get_class_methods($Bootstrap);
foreach ($bootstrap_methods as $method) {
if(substr($method,0,5) == '_init'){
$bootstrap->$method();
}
}
return true;
}
}
Here's the test:
require_once dirname(__FILE__).'/../../../public/bootstrap.php';
require_once dirname(__FILE__).'/../../../library/SKL/Application.php';
class SKL_ApplicationTest extends PHPUnit_Framework_TestCase {
protected $object;
protected function setUp() {
$this->object = new SKL_Application();
}
/**
* Tears down the fixture, for example, closes a network connection.
* This method is called after a test is executed.
*/
protected function tearDown() {
}
public function testInitialise() {
$this->assertType('boolean',$this->object->initialise());
}
}
But I keep stumbling at the first hurdle!!
PHP Warning: include(bootstrap.php): failed to open stream:
No such file or directory in path\to\files\SKL\Application.php on line 9
any ideas?
Use include_once or better yet require_once instead of include to include the bootstrap.php in the Application class file. Despite being already loaded include loads it again but since it's obviously not on the include path you get the error.
Thanks to Raoul Duke for giving me a push in the right direction, here's where I got to so far
1 - add the root of the application to the include path
2 - make all inclusion paths relative to the root of the application
3 - include a file in your unit tests that performs the same function, but compensates for the relative location when it is included. I just used realpath() on the directory location of the files.
The problem I have now is that the darn thing won't see any additional files I'm trying to pass it.
So, I'm trying to test a configuration class, that will parse a variety of filetypes dynamically. The directory structure is like this:
Application_ConfigTest.php
config.ini
The first test:
public function testParseFile() {
$this->assertType('array',$this->object->parseFile('config.ini'));
}
The error:
failed to open stream: No such file or directory
WTF? It's IN the same directory as the test class...
I solved this by providing an absolute (i.e. file structure) path to the configuration file.Can anyone explain to me how PHPUnit resolves it's paths, or is it because the test class itself is included elsewhere, rendering relative paths meaningless?

Resources