Detect when bind occurs in mvvmcross - mvvmcross

Hi i need to intercept when bind occur in mvvmcross project.
I have my MvxCollectionViewCell that i bind:
public ProjectsCollectionCell (IntPtr handle)
: base (string.Empty, handle)
{
this.DelayBind(() => {
var set = this.CreateBindingSet<ProjectsCollectionCell, ViewItem>();
set.Bind (lblTitle).To (prj => prj.MnemonicId);
set.Bind (lblDescription).To (prj => prj.Description);
set.Bind(imgPhoto).For (s => s.Image).WithConversion("ImageArray").To(prj => prj.Image);
set.Apply();
if (imgPhoto.Image != null) {
this.imgPhoto.Layer.RasterizationScale = UIScreen.MainScreen.Scale;
this.imgPhoto.Layer.ShouldRasterize = true;
this.imgPhoto.Layer.BorderWidth = 10;
this.imgPhoto.Layer.BorderColor = UIColor.White.CGColor;
this.imgPhoto.Layer.CornerRadius = 8f;
this.imgPhoto.Layer.MasksToBounds = true;
this.imgPhoto.Layer.Position = new PointF(imgPhoto.Frame.Left - 80, imgPhoto.Frame.Bottom);
this.imgPhoto.Transform = CGAffineTransform.MakeRotation(-0.05f);
};
});
}
i want to intercept when the content of the 'imgPhoto' change.
Is there an event to subscribe?
Could you suggest me how to do this?

If you need to detect when the Image on your cell's DataContext changes, then one way to do this is to add the property to your cell and to bind that property to your DataContext - e.g.
private byte[] _bytes;
public byte[] Bytes
{
get { return _bytes; }
set
{
_bytes = value;
// your code here...
}
}
public ProjectsCollectionCell (IntPtr handle)
: base (string.Empty, handle)
{
this.DelayBind(() => {
var set = this.CreateBindingSet<ProjectsCollectionCell, ViewItem>();
set.Bind(_hook).For(h => h.CurrentSource);
set.Bind (lblTitle).To (prj => prj.MnemonicId);
set.Bind (lblDescription).To (prj => prj.Description);
set.Bind(this).For(s => s.Bytes).WithConversion("ImageArray").To(prj => prj.Image);
set.Apply();
// etc
});
}
As an alternative, you might also want to consider subclassing whatever type imgPhoto is and providing a new property on that object. For an example of this approach, see the AnimatingText properties in http://slodge.blogspot.co.uk/2013/07/n33-animating-data-bound-text-changes.html

Related

How to avoid general Function type in angular

I'm using eslint and it states that using 'Function' as a type is unsafe.
Is there a better way of doing this, so that I don't use the function type:
I have this confirmation dialog that appears when I'm trying to delete something:
export class DialogConfirmationComponent {
message: string = "";
txtBtnConfirmation: string = "Confirm";
actionConfirm: Function = () => { };
actionCancel: Function = () => { };
}
And when I click on the confirm button on the html this actionConfirm Function is called.
I want it to be generic so that I can call this dialog for different components and uses, and define the action using bind on the component, like this:
export class ItemCardComponent {
constructor(
private dialog: MatDialog
) { }
public openDeleteDialog(item: Item): void {
const dialogRef = this.dialog.open(DialogConfirmationComponent, {
width: '500px',
panelClass: 'no-padding-dialog',
autoFocus: false
});
dialogRef.componentInstance.message= "Are you sure?";
dialogRef.componentInstance.txtBtnConfirmation = "Delete";
dialogRef.componentInstance.actionConfirm = this.delete.bind(this, item);
}
private delete(item: Item): void {
// ToDo: delete
}
}
So far it's working, but is there a better way of doing it without using the Function type?
You could use this if the function is very general and you are unsure of the number and type of parameters or the nature of the return type:
(...args: any[]) => any
However, if you are aware of the return type, you may use this in its place. Note that the return type in this case is void:
(...args: any[]) => void
If you want to boost type safety, you may also replace any with types. In this example, you are presuming that the parameters are of the type number or string and that the return type is unknown.
(...args: (string & number)[]) => unknown

Download CSV in Mezzio Framework (Zend/Laminas)

In Mezzion Framework I have the next Handler:
<?php
namespace Bgc\Handler;
use App\Service\GenerateReportToCSV;
use Bgc\Queue\BGCQueueManager;
use Laminas\Diactoros\Response\TextResponse;
use League\Csv\Writer;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
class DownloadBgcReportHandler implements RequestHandlerInterface
{
protected $bgcQManager;
protected $reportToCSV;
public function __construct(BGCQueueManager $bgcQManager, $reportToCSV)
{
$this->bgcQManager = $bgcQManager;
$this->reportToCSV = $reportToCSV;
}
public function handle(ServerRequestInterface $request): TextResponse
{
$queryParams = $request->getQueryParams();
$params = [];
if (isset($queryParams['startDate'])) {
$starDate = new \DateTime($queryParams['startDate']);
$params['startDate'] = $starDate->modify('midnight');
}
if (isset($queryParams['startDate'])) {
$endDate = new \DateTime($queryParams['endDate']);
$params['endDate'] = $endDate->modify('tomorrow');
}
$itemsBGC = $this->bgcQManager->getDataToDownload($params);
$time = time();
$fileName = "bgc-report-$time.csv";
$csv = Writer::createFromFileObject(new \SplFileObject());
$csv->insertOne($this->reportToCSV->getHeadingsBGC());
foreach ($itemsBGC as $item) {
$csv->insertOne($item);
}
return new TextResponse($csv->getContent(), 200, [
'Content-Type' => 'text/csv',
'Content-Transfer-Encoding' => 'binary',
'Content-Disposition' => "attachment; filename='$fileName'"
]);
}
}
I have the below error:
Whoops\Exception\ErrorException: Declaration of Bgc\Handler\DownloadBgcReportHandler::handle(Psr\Http\Message\ServerRequestInterface $request): Laminas\Diactoros\Response\TextResponse must be compatible with Psr\Http\Server\RequestHandlerInterface::handle(Psr\Http\Message\ServerRequestInterface $request): Psr\Http\Message\ResponseInterface in file /home/peter/proyectos/revelations-thena-api/src/Bgc/src/Handler/DownloadBgcReportHandler.php on line 20
I don't know, to create a downloable file. The hadbler works fine with Json. I tried to change from ResponseInterface to TextResponse.
How can I download file CSV?
Thank you
The error you received is telling you that your method signature is not compliant to interface's method signature.
RequestHandlerInterface:
interface RequestHandlerInterface
{
public function handle(ServerRequestInterface $request): ResponseInterface;
}
As you see, the signature states that an object of type ResponseInterface is returned.
You modified the signature:
class DownloadBgcReportHandler implements RequestHandlerInterface
{
public function handle(ServerRequestInterface $request): TextResponse;
}
The signature must be the same, but then you can return the TextResponse without problem (since it extends Laminas\Diactoros\Response, which implements Psr\Http\Message\ResponseInterface)
Just change that and it will works :)
You have modified you handle method, so right now you aren't fulfilling the requirements of the RequestHandlerInterface
Replace the return value for the handler with ResponseInterface enforced in the interface: RequestHandlerInterface
so i think you are best helped with:
<?php
namespace Bgc\Handler;
use App\Service\GenerateReportToCSV;
use Bgc\Queue\BGCQueueManager;
use Laminas\Diactoros\Response;
use Laminas\Diactoros\Stream;
use League\Csv\Writer;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
class DownloadBgcReportHandler implements RequestHandlerInterface
{
protected $bgcQManager;
protected $reportToCSV;
public function __construct(BGCQueueManager $bgcQManager, $reportToCSV)
{
$this->bgcQManager = $bgcQManager;
$this->reportToCSV = $reportToCSV;
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
$queryParams = $request->getQueryParams();
$params = [];
if (isset($queryParams['startDate'])) {
$starDate = new \DateTime($queryParams['startDate']);
$params['startDate'] = $starDate->modify('midnight');
}
if (isset($queryParams['startDate'])) {
$endDate = new \DateTime($queryParams['endDate']);
$params['endDate'] = $endDate->modify('tomorrow');
}
$itemsBGC = $this->bgcQManager->getDataToDownload($params);
$time = time();
$fileName = "bgc-report-$time.csv";
// $csv = Writer::createFromFileObject(new \SplFileObject());
// $csv->insertOne($this->reportToCSV->getHeadingsBGC());
$csv = Writer::createFromString($this->reportToCSV->getHeadingsBGC());
foreach ($itemsBGC as $item) {
$csv->insertOne($item);
}
$body = new Stream($csv->getContent());
return new Response($body, 200, [
'Cache-Control' => 'must-revalidate',
'Content-Disposition' => 'attachment; filename=' . $fileName,
'Content-Length' => strval($body->getSize()),
'Content-Type' => 'text/csv',
'Content-Transfer-Encoding' => 'binary',
'Expires' => '0',
'Pragma' => 'public',
]);
}
}
PS: i have commented the 2 lines in which an empty new \SplFileObject() was used, because the required param $filename was empty (and i did not want to make a decision there) and added a line with Writer::createFromString().

Return JsonResponse when i use an AuthTokenAuthenticator (symfony 3)

I specify that I start with Symfony. I want to create an API (without FOSRestBundle) with a token as a means of authentication.
I followed different tutorials for this set up. What I would like is when there is an error that is picked up by the class "AuthTokenAuthenticator", it is returned a json and not a html view.
Here are my script:
AuthTokenAuthenticator
namespace AppBundle\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
use Symfony\Component\Security\Http\Authentication\SimplePreAuthenticatorInterface;
use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Component\HttpFoundation\JsonResponse;
class AuthTokenAuthenticator implements
SimplePreAuthenticatorInterface, AuthenticationFailureHandlerInterface
{
const TOKEN_VALIDITY_DURATION = 12 * 3600;
protected $httpUtils;
public function __construct(HttpUtils $httpUtils)
{
$this->httpUtils = $httpUtils;
}
public function createToken(Request $request, $providerKey)
{
//$targetUrlToken = '/auth-tokens'; // login
//$targetUrlUser = '/users/create'; // create account
/*if ($request->getMethod() === "POST" && $this->httpUtils->checkRequestPath($request, $targetUrlUser) || $request->getMethod() === "POST" && $this->httpUtils->checkRequestPath($request, $targetUrlToken) ) {
return;
}*/
$authTokenHeader = $request->headers->get('X-Auth-Token');
if (!$authTokenHeader) {
//return new JsonResponse(array("error" => 1, "desc" => "INVALID_TOKEN", "message" => "X-Auth-Token header is required"));
throw new BadCredentialsException('X-Auth-Token header is required');
}
return new PreAuthenticatedToken(
'anon.',
$authTokenHeader,
$providerKey
);
}
public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
{
if (!$userProvider instanceof AuthTokenUserProvider) {
throw new \InvalidArgumentException(
sprintf(
'The user provider must be an instance of AuthTokenUserProvider (%s was given).',
get_class($userProvider)
)
);
}
$authTokenHeader = $token->getCredentials();
$authToken = $userProvider->getAuthToken($authTokenHeader);
if (!$authToken || !$this->isTokenValid($authToken)) {
throw new BadCredentialsException('Invalid authentication token');
}
$user = $authToken->getUser();
$pre = new PreAuthenticatedToken(
$user,
$authTokenHeader,
$providerKey,
$user->getRoles()
);
$pre->setAuthenticated(true);
return $pre;
}
public function supportsToken(TokenInterface $token, $providerKey)
{
return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey;
}
/**
* Vérifie la validité du token
*/
private function isTokenValid($authToken)
{
return (time() - $authToken->getCreatedAt()->getTimestamp()) < self::TOKEN_VALIDITY_DURATION;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
throw $exception;
}
}
Here is the error return that I have when I do not inform the token:
<!DOCTYPE html>
<html>
<head>
<title> X-Auth-Token header is required (500 Internal Server Error)
How can i do to get a return json response ?
If i try to do a return new JsonResponse(array("test" => "KO")) (simple example), i get this error:
<title> Type error: Argument 1 passed to Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager::authenticate() must be an instance of Symfony\Component\Security\Core\Authentication\Token\TokenInterface, instance of Symfony\Component\HttpFoundation\JsonResponse given, called in /Users/mickaelmercier/Desktop/workspace/api_monblocrecettes/vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php on line 101 (500 Internal Server Error)
You can create your own Error Handler. It's a event listener or subscriber that listens to kernel.exception, when it adds a response to the event, the event propagation is stopped, so the default error handler will not be triggered.
It could look something like this:
<?php declare(strict_types = 1);
namespace App\EventSubsbscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\KernelEvents;
final class ExceptionToJsonResponseSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
KernelEvents::EXCEPTION => 'onKernelException',
];
}
public function onKernelException(GetResponseForExceptionEvent $event): void
{
// Skip if request is not an API-request
$request = $event->getRequest();
if (strpos($request->getPathInfo(), '/api/') !== 0) {
return;
}
$exception = $event->getException();
$error = [
'type' => $this->getErrorTypeFromException($exception),
// Warning! Passing the exception message without checks is insecure.
// This will potentially leak sensitive information.
// Do not use this in production!
'message' => $exception->getMessage(),
];
$response = new JsonResponse($error, $this->getStatusCodeFromException($exception));
$event->setResponse($response);
}
private function getStatusCodeFromException(\Throwable $exception): int
{
if ($exception instanceof HttpException) {
return $exception->getStatusCode();
}
return 500;
}
private function getErrorTypeFromException(\Throwable $exception): string
{
$parts = explode('\\', get_class($exception));
return end($parts);
}
}
ApiPlatform provides its own exception listener like this, that is more advanced, that you could look into if you need "better" exception responses.

.NET Core - SerializerSettings not being applied

Startup.cs
services.AddMvc().AddJsonOptions(options => {
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
});
Random class
JsonConvert.SerializeObject(configItem)
SerializerSettings are not being applied -> null values are not ignored.
Inside startup.cs:
JsonConvert.DefaultSettings = () => {
return new JsonSerializerSettings() {
NullValueHandling = NullValueHandling.Ignore
};
};
To apply global JsonConvert settings.

Serialize Object like a form in as3

I am looking to transmit a post request through HTTP, the body needs to contain information from a ValueObject I've already created. Essentially I need to serialize the object (which has multiple dimensions). The problem I'm running into is that I don't want to transmit the data as JSON or XML but as a multidimensional array. It works in HTML forms like:
data:
Array
(
[a] => Array
(
[a] => Array
(
[1] => abcd
)
[b] => defg
)
[d] => ghij
)
request body (decoded):
a[a][1]=abcd&a[b]=defg&d=ghij
Is there any library out there that does this kind of serialization already? I'm using as3httpclientlib, so I don't have the convenience of the mx.rpc family. I've spent the past several hours trying to roll my own solution, but I'm pretty sure I'd be better off with a solution someone has put more time and thought into.
You can try AMF to solve your problem (you have different library according to your programming language).
The main advantage is that you can do mapping object to object (using Value Object) and preserve the data type (like arrays).
I'm using the plugin amf with Symfony and here is an example of data returned :
SabreAMF_TypedObject Object
(
[amfClassName:private] => Product
[amfData:private] => Array
(
[code] => 1970A007
[designation] => 1970 PELL A007 BLANC
[description] => Vernis extra souple extra brillant
[sommeil] =>
[name] => 1970
[base] => A Stretch Enduit
[composition] => 43% PL 57% PU
[laize] => 137-140 cm
[weight] => 588 g/ml
[dechirure] => 10 daN/9 daN
[abrasion] => 5000
[xenotest] => 4/5
[non_feu] => Non
[Color] => SabreAMF_TypedObject Object
(
[amfClassName:private] => Color
[amfData:private] => Array
(
[id] => 124
[name] => BLANC
)
)
Some explanation :
[amfClassName:private] => Product
My Object is typed. As3 side i have a Product Value Object too wich contains array properties like "code", "designation", "description",... and Color (another typed Array with Value Object Color)
So you can easily have a multidimensional structure arrays...
Ok,
so here is something more simple using URLVariables :
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLRequestMethod;
import flash.net.URLVariables;
public class URLVariableExample extends Sprite {
private static const URL_SERVER:String = "http://localhost/testURL.php";
private var loader:URLLoader;
public function URLVariableExample() {
init();
}
private function init() : void {
var request:URLRequest = new URLRequest(URL_SERVER);
var urlVar:URLVariables = new URLVariables();
var a : Array = ["toto", "titi", "loulou"];
urlVar["urlTest[a][a]"] = a.toString();
urlVar["urlTest[a][b]"] = "desc";
urlVar["urlTest[d]"] = "defg";
request.data = urlVar;
request.method = URLRequestMethod.POST;
loader = new URLLoader();
loader.addEventListener(Event.COMPLETE, loaderComplete);
loader.load(request);
}
private function loaderComplete(event : Event) : void {
loader.removeEventListener(Event.COMPLETE, loaderComplete);
trace(URLLoader(event.currentTarget).data);
}
}
}
I requested a php file and just put a simple var_dump function.
Trace return :
array(2) {["d"]=>string(4) "defg"["a"]=> array(2) {["a"]=>string(16) "toto,titi,loulou["b"]=>string(4) "desc"}}
var url:String = 'http://localhost/dump.php';
var params:Object = {
test: 'ok',
nested_1: {
nested_2: {
nested_3: {
nested_4: {
hello: 'mf',
str: '~!##$%^&*()_+'
}
}
}
},
};
var request:URLRequest = new URLRequest(url);
var variables:URLVariables = new URLVariables();
parameters = fixParameters(parameters || {});
for (var key:String in parameters) {
variables[key] = parameters[key];
}
request.data = variables;
var loader:URLLoader = new URLLoader();
loader.load(request);
and here is fixParameters method
private function fixParameters(data:Object, parameters:Object = null, prefixes:Array = null):Object {
var setPrefix:Array;
var prefixKey:String;
if (!parameters) {
parameters = {};
}
if (!prefixes) {
prefixes = [];
}
for (var key:String in data) {
setPrefix = prefixes.concat([key]);
if (typeof(data[key]) == 'object') {
parameters = fixParameters(data[key], parameters, setPrefix);
} else {
prefixKey = '';
for (var i:Number = 0; i < setPrefix.length; i++) {
prefixKey += i == 0 ? setPrefix[i] : '[' + setPrefix[i] + ']';
}
parameters[prefixKey] = data[key];
}
}
return parameters;
}