#Debug metadata crashes with TypeError - haxe

I have a problem with working with the automatic logging using #Debug metadata.
I'm receiving following error:
TypeError: Cannot read property 'debug' of null - Which after some digging into generated code indicates that the logger is null.
This is my setup:
class SomeView implements ISomeView implements IsLoggable implements IInjectorContainer
{
var _view:Component;
public function new()
{
}
#Debug public function showNumber(number:Float):Void
{
//trace('number is: $number');
}
}
In DSL I have this:
<view id="someView" type="my.views.SomeView />
<config id="someViewConfig" type="hex.ioc.di.MappingConfiguration" >
<item map-name="normal" inject-into="true">
<key type="Class" value="my.views.ISomeView"/>
<value ref="someView"/>
</item>
</config>
As far as I understand this should make sure that I have the logger injected.
I've also tried calling _injector.injectInto(_myView); in my module which is also not solving the problem.
Anyone knows how to enable the automatic debug calls?

I opened an issue here.
"It's related to interfaces implementation order. When IInjectorContainer (building macro) is executed before IsLoggable one, logger property is not added to refection data and cannot be injected later."
Thanks for your feedback.

Related

Shopware How to get SalesChannelContext in OrderWrittenEvent in order to send Mail?

I have a situation where I want to send emails from the order written event whenever an order has been updated according to some set of conditions that I will implement (for example an API response error) But unfortunately I have been unable to do so.
I first created a controller and an email service which uses the abstract email service of shopware And from my controller I'm able to send an email But when I tried to do the same in the event,I quickly realized that it wasn't doing exactly what I was expecting it to do. After some research on it, I saw that the event actually don't have access to the sales channel context so I tried multiple different ways to solve this issue but I'm still stuck. Can somebody please guide me on how I can implement that? thank you very much.
an example of what I tried is to call the store API in order to get the context of the saleschannel to use it in my sendMail function But it was giving errors such as:
request.CRITICAL: Uncaught PHP Exception TypeError: "Argument 5 passed to Swag\BasicExample\Service\EmailService::sendMail() must be an instance of Shopware\Core\System\SalesChannel\SalesChannelContext, instance of stdClass given.
I obviously understand that I have to give it a Shopware\Core\System\SalesChannel\SalesChannelContext not an STD class but how can I do that? since it doesn't really see the channel context.
If you do have an instance of OrderEntity you can rebuild the SalesChannelContext from the existing order using the OrderConverter service.
<service id="Foo\MyPlugin\Subscriber\MySubscriber">
<argument type="service" id="Shopware\Core\Checkout\Cart\Order\OrderConverter"/>
<argument type="service" id="order.repository"/>
<tag name="kernel.event_subscriber"/>
</service>
class MySubscriber implements EventSubscriberInterface
{
private OrderConverter $orderConverter;
private EntityRepository $repository;
public function __construct(
OrderConverter $orderConverter,
EntityRepository $repository
) {
$this->orderConverter = $orderConverter;
$this->repository = $repository;
}
public static function getSubscribedEvents(): array
{
return [
OrderEvents::ORDER_WRITTEN_EVENT => 'onOrderWritten',
];
}
public function onOrderWritten(EntityWrittenEvent $event): void
{
foreach ($event->getWriteResults() as $writeResult) {
$orderId = $writeResult->getPrimaryKey();
$criteria = new Criteria([$orderId]);
$criteria->addAssociation('transactions');
$criteria->addAssociation('orderCustomer');
$order = $this->repository
->search($criteria, $event->getContext())->first();
if (!$order instanceof OrderEntity) {
continue;
}
$salesChannelContext = $this->orderConverter
->assembleSalesChannelContext($order, $event->getContext());
// ...
}
}
}

Why isn't my custom macro showing up at template explorer?

I am trying to develop a macro for c# templates, but it simply doesn't work. I have tried reading the whole (incomplete) documentation, or find the source code of a macro to use as an example, but I failed on both.
I am able to build, install and debug the plugin. No errors, and both constructors and methods are called. But when I access the macros inside the templates explorer, nothing shows up there. I have also selected All macros from the options.
Here is my code
MyMacroDefinition.cs
[MacroDefinition("Subeta.Abp.ReSharper", LongDescription = "Long Description", Name = "My Name", Requirement = InstantiationRequirement.Instant, ShortDescription = "Short Description")]
public class MyMacroDefinition : SimpleMacroDefinition
{
public MyMacroDefinition()
{
}
}
MyMacroImplementation.cs
[MacroImplementation(Definition = typeof(MyMacroDefinition), Requirement = InstantiationRequirement.Instant)]
public class MyMacroImplementation : SimpleMacroImplementation
{
private IMacroParameterValueNew myArgument;
public MyMacroImplementation([Optional] MacroParameterValueCollection arguments)
{
myArgument = arguments.OptionalFirstOrDefault();
}
public override string EvaluateQuickResult(IHotspotContext context)
{
return myArgument == null ? null : myArgument.GetValue().ToUpperInvariant();
}
}
Subeta.Abp.ReSharper.nuspec
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Subeta.Abp.ReSharper</id>
<title>Abp Support</title>
<version>1.0.2</version>
<authors>Subeta</authors>
<owners>Subeta</owners>
<summary>ReSharper support for ASP.NET Boilerplate framework</summary>
<description>
Required desc
</description>
<releaseNotes>
</releaseNotes>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<dependencies>
<dependency id="Wave" version="[11.0]" />
</dependencies>
<tags>aspnetboilerplate abp</tags>
</metadata>
<files>
<file src="bin\Debug\Subeta.Abp.ReSharper.dll" target="DotFiles" />
<file src="bin\Debug\Subeta.Abp.ReSharper.pdb" target="DotFiles" />
</files>
</package>
Thanks in advance!
Does the plugin get loaded by ReSharper at all? You need to make sure you have "zones" set up. Check this Troubleshooting guide for reasons why it might not have installed correctly.

How can I include xml configuration in logback.groovy

I'm writing a Spring Boot app and need the flexibility of controlling my logback configuration using Groovy. In Spring Boot all I have to do is create src/main/resources/logback.groovy and it is automatically used for configuration.
What I would like to do though is start with Spring Boot's default logback configuration, and just override or modify settings as needed.
If I were using logback.xml instead of logback.groovy I could do something like the following.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="org.springframework.web" level="DEBUG"/>
</configuration>
Is there something similar to the include line above that I can use in logback.groovy? I can look at the contents of base.xml and it's other included files to see how to replicate this manually, but it would add a bit of boilerplate code I'd like to avoid.
Thanks for any help you can provide.
There's an online tool that translates given logback.xml file to equivalent logback.groovy. In your case it resulted in:
//
// Built on Thu Jul 16 09:35:34 CEST 2015 by logback-translator
// For more information on configuration files in Groovy
// please see http://logback.qos.ch/manual/groovy.html
// For assistance related to this tool or configuration files
// in general, please contact the logback user mailing list at
// http://qos.ch/mailman/listinfo/logback-user
// For professional support please see
// http://www.qos.ch/shop/products/professionalSupport
import static ch.qos.logback.classic.Level.DEBUG
logger("org.springframework.web", DEBUG)
When it comes to <include> it's not supported for groovy configurations.
How do you feel about instead of adding/overriding your configuration, you reload it again?
You can create a Spring Bean that will see if a logback file is in a location you specify, and if it is, reload using that file
Example
#Component
public class LoggingHelper {
public static final String LOGBACK_GROOVY = "logback.groovy";
#PostConstruct
public void resetLogging() {
String configFolder = System.getProperty("config.folder");
Path loggingConfigFile = Paths.get(configFolder, LOGBACK_GROOVY);
if (Files.exists(loggingConfigFile) && Files.isReadable(loggingConfigFile)) {
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
ContextInitializer ci = new ContextInitializer(loggerContext);
loggerContext.reset();
try {
ci.configureByResource(loggingConfigFile.toUri().toURL());
} catch (JoranException e) {
// StatusPrinter will handle this
} catch (MalformedURLException e) {
System.err.println("Unable to configure logger " + loggingConfigFile);
}
StatusPrinter.printInCaseOfErrorsOrWarnings(loggerContext);
}
}
}
I am using this snippet to start my logback.groovy file
import ch.qos.logback.classic.joran.JoranConfigurator
import org.xml.sax.InputSource
def configurator = new JoranConfigurator()
configurator.context = context
def xmlString = '<?xml version="1.0" encoding="UTF-8"?>\n<configuration>\n <include resource="org/springframework/boot/logging/logback/base.xml"/>\n</configuration>'
configurator.doConfigure(new InputSource(new StringReader(xmlString)))
Contrary to the documentation stating that:
Everything you can do using XML in configuration files, you can do in
Groovy with a much shorter syntax.
include is not possible with Groovy out-of-the-box. However, thanks to a bug ticket that was opened in 2014, there are a couple of workarounds. I am including them here (slightly edited), but all credit goes to "Yih Tsern" from the original JIRA bug:
logback.groovy
include(new File('logback-fragment.groovy'))
root(DEBUG, ["CONSOLE"])
def include(File fragmentFile) {
GroovyShell shell = new GroovyShell(
getClass().classLoader,
binding,
new org.codehaus.groovy.control.CompilerConfiguration(scriptBaseClass: groovy.util.DelegatingScript.name))
Script fragment = shell.parse(fragmentFile.text)
fragment.setDelegate(this)
fragment.run()
}
logback-fragment.groovy:
// NOTE: No auto-import
import ch.qos.logback.core.*
import ch.qos.logback.classic.encoder.*
appender("CONSOLE", ConsoleAppender) {
encoder(PatternLayoutEncoder) {
pattern = "%d [%thread] %level %mdc %logger{35} - %msg%n"
}
}
Given the workaround and a pull-request to add the feature, I'm not sure why the functionality hasn't been added to Logback core yet.

Using Symfony2's AccessDeniedHandlerInterface

I am trying to get my security stuff setup for symfony2 and I have it working so far, but now I need to do some more fancy things. I am currently using everything dealing with PreAuthentication (I use a third party component for logging in and session management). That part is working great in tandem with the JMS security bundle.
Now I am to the point when I want to catch the users that are throwing 403s so I can just forward them to the login page of the third party component that I am using. I think my best bet is to add an exception handler to the exception listener. I am looking at the AccessDeniedHandlerInterface.
Is this the right direction for me to be going?
How do I add this handler to the exception listener?
EDIT:
I ended up doing something similar. I created a service that is prompted on the kernel.exception event. services.yml looks like this:
services:
kernel.listener.accessDenied:
class: Fully\Qualified\Namespace\Path\To\Class
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onAccessDeniedException }
and the class it self:
<?php
namespace Fully\Qualified\Namespace\Path\To;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent,
Symfony\Component\HttpFoundation\Response,
Symfony\Component\Security\Core\Exception\AccessDeniedException;
class Class
{
public function onAccessDeniedException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
//Get the root cause of the exception.
while (null !== $exception->getPrevious()) {
$exception = $exception->getPrevious();
}
if ($exception instanceof AccessDeniedException) {
//Forward to third-party.
}
}
}
This sounds about right.
Or, if you're specifically interested in AccessDeniedException you could also define access_denied_handler within your firewall in security.yml:
security:
firewalls:
my_firewall:
# ...
access_denied_handler: kernel.listener.access_denied.handler
# ...
Then define your service in your services.xml or equivalent:
<parameters>
<parameter key="kernel.listener.security.class">Path\To\Your\Class</parameter>
</parameters>
<service id="kernel.listener.access_denied.handler" class="%kernel.listener.security.class%">
<tag name="kernel.event_listener" event="security.kernel_response" method="handle" />
</service>
The handler class:
use \Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface;
class MyAccessDeniedHandler implements AccessDeniedHandlerInterface
{
public function handle(Request $request, AccessDeniedException $accessDeniedException)
{
// do something with your exception and return Response object (plain message of rendered template)
}
}
You can find complete Security reference of Symfony2 here: http://symfony.com/doc/2.8/reference/configuration/security.html

Getting values from Log4Net configuration

I have implement a custom log4net appender by extending the AppenderSkeleton-class. It was as simple as anyone could ask for and works perfectly.
My problem is that I had to hardcode a few values and I'd like to remove them from my code to the configuration of the appender. Since log4net knows how it is configured I think there should be a way to ask log4net for it's configuraion.
My appender could look something like this:
<appender name="MyLogAppender" type="xxx.yyy.zzz.MyLogAppender">
<MyProperty1>property</MyProperty1>
<MyProperty2>property</MyProperty2>
<MyProperty3>property</MyProperty3>
</appender>
How to get the value of MyProperty1-3 so I can use it inside my Appender?
Thanks in advance
Roalnd
It depends a bit on the type but for simple types you can do the following:
Define a property like this:
// the value you assign to the field will be the default value for the property
private TimeSpan flushInterval = new TimeSpan(0, 5, 0);
public TimeSpan FlushInterval
{
get { return this.flushInterval; }
set { this.flushInterval = value; }
}
This you can configure as follows:
<appender name="MyLogAppender" type="xxx.yyy.zzz.MyLogAppender">
<flushInterval value="02:45:10" />
</appender>
This certainly works for string, bool, int and TimeSpan.
Note: If your settings requires some logic to be activated (e.g. create a timer) then you can implement this in the ActivateOptions method.

Resources