How to build Excel with two sheets and download? - excel

I use Laravel Excel and that is full code:
<?php
namespace App\Http\Controllers;
use App\Event;
use App\Visitor;
use Illuminate\Support\Facades\Storage;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithTitle;
use Maatwebsite\Excel\Facades\Excel;
use Exportable;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
class VisitorsSheet implements FromQuery, WithTitle
{
private $idEvent;
public function __construct($idEvent)
{
$this->idEvent = $idEvent;
}
public function query()
{
return Visitor::where("idEvent", $this->idEvent)->get();
}
public function title(): string
{
return 'Visitors';
}
}
class EventSheet implements FromQuery, WithTitle
{
private $idEvent;
public function __construct($idEvent)
{
$this->idEvent = $idEvent;
}
public function query()
{
return Event::where("idEvent", $this->idEvent)->get();
}
public function title(): string
{
return 'Event №' . $this->idEvent;
}
}
class ArchivingExport implements WithMultipleSheets
{
private $eventId;
public function __construct($eventId)
{
$this->eventId = $eventId;
}
public function sheets(): array
{
$sheets = [];
$sheets[] = new EventSheet($this->eventId);
$sheets[] = new VisitorsSheet($this->eventId);
return $sheets;
}
}
class ArchivingController extends Controller
{
private $file = "settings_archive.json";
public function __construct()
{
date_default_timezone_set("Asia/Tei");
}
private function formatName($event)
{
return $event->date . '_' . $event->name . '.xlsx';
}
public function index()
{
$download = [];
try {
$events = Event::where("status", 1)->where("archived", 0)->get();
foreach ($events as $key => $event) {
$download[] = new ArchivingExport($event->idEvent); //->download($this->formatName($event));
}
return $download;
} catch (Exception $e) {
return \json_decode([
'status' => false,
'message' => $e->getMessage()
]);
}
return \json_decode([
'status' => false
]);
}
}
As you can see in class ArchivingController in index method I try to build sheets:
foreach ($events as $key => $event) {
$download[] = new ArchivingExport($event->idEvent); //->download($this->formatName($event));
}
I get ready objects in $download[], but I dont know how to download them? It should be ready Excel file.
I tried to call for each object:
->download($this->formatName($event));
But there is not method download inside

It is not possible to send more than one file simultaneously over the same request with the HTTP protocol. Laravel also does not support this.
You have to pack the files in, for example, a zip file.
A popular package is Zipper

Related

Orchard ICustomVirtualPathProvider

I am trying to register a ICustomVirtualPathProvider in one of my modules. This is what I am trying to use:
public class AzureVirtualPathProvider : VirtualPathProvider, ICustomVirtualPathProvider
{
public IStaticDataStorageProvider StaticDataStorageProvider { get; set; }
public VirtualPathProvider Instance
{
get
{
return this;
}
}
public AzureVirtualPathProvider(IStaticDataStorageProvider staticDataStorageProvider)
{
StaticDataStorageProvider = staticDataStorageProvider;
}
public override bool FileExists(string virtualPath)
{
if (!virtualPath.Contains("StaticData")) return base.FileExists(virtualPath);
return true;
}
public override VirtualFile GetFile(string virtualPath)
{
if (!virtualPath.Contains("StaticData") || !StaticDataStorageProvider.IsCloud()) return base.GetFile(virtualPath);
return new CustomVirtualFile(StaticDataStorageProvider, virtualPath);
}
}
so in Module.Load I am setting:
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<AzureVirtualPathProvider>().PropertiesAutowired().As<ICustomVirtualPathProvider>();
}
but this has not been picked up when Orchard calls this line in OrchardStartup.cs (in Orchard.Framework)
if (HostingEnvironment.IsHosted) {
foreach (var vpp in container.Resolve<IEnumerable<ICustomVirtualPathProvider>>()) {
HostingEnvironment.RegisterVirtualPathProvider(vpp.Instance);
}
}
I haver tried calling HostingEnvironment.RegisterVirtualPathProvider directly thus:
HostingEnvironment.RegisterVirtualPathProvider(new AzureVirtualPathProvider());
and tried to inject the dependency using property injecction:
builder.Register(c => new AzureVirtualPathProvider { StaticDataStorageProvider = c.Resolve<IStaticDataStorageProvider>() });
however the value for StaticDataStorageProvider is always null when AzureVirtualPathProvider is run.
I have tried moving AzureVirtualPathProvider to OrchardFramework but then it does not resolve StaticDataStorageProvider.
How do I get Orchard to load my CustomVirtualPathProvider?
In the end I did this:
public class OrchardShellEvents : IOrchardShellEvents
{
readonly ICustomVirtualPathProvider _customVirtualPathProvider;
public OrchardShellEvents(ICustomVirtualPathProvider customVirtualPathProvider)
{
_customVirtualPathProvider = customVirtualPathProvider;
}
public void Activated()
{
HostingEnvironment.RegisterVirtualPathProvider(_customVirtualPathProvider.Instance);
}
public void Terminating()
{
}
}
I don't know if this is the best solution but it worked and might help someone else.

Authorize if not in specific role attribute MVC 5

I need authorization attribute for action which allows all but specific role.
something like
[!Authorize(Roles = "SuperUser")]
public ActionResult PaySuperUser.....
Anything built in?
Or any suggestion for custom attribute?
I think a custom attribute is a way to go.
Here is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Controllers;
namespace YourFancyNamespace
{
public class AuthorizeExtended : AuthorizeAttribute
{
private string _notInRoles;
private List<string> _notInRolesList;
public string NotInRoles
{
get
{
return _notInRoles ?? string.Empty;
}
set
{
_notInRoles = value;
if (!string.IsNullOrWhiteSpace(_notInRoles))
{
_notInRolesList = _notInRoles
.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries)
.Select(r => r.Trim()).ToList();
}
}
}
public override void OnAuthorization(HttpActionContext actionContext)
{
base.OnAuthorization(actionContext);
if (_notInRolesList != null && _notInRolesList.Count > 0)
{
foreach (var role in _notInRolesList)
{
if (actionContext.RequestContext.Principal.IsInRole(role))
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
}
}
}
}
}
}
And here is how you can use it:
// A AuthorizeExtended equals Authorize(with Role filter) + exclude all pesky users
[AuthorizeExtended(Roles = "User", NotInRoles="PeskyUser")]
[HttpPost]
[Route("api/Important/DoNotForgetToUpvote")]
public async Task<IHttpActionResult> DoNotForgetToUpvote()
{
return Ok("I did it!");
}
// Б AuthorizeExtended equals plain Authorize + exclude all pesky users
[AuthorizeExtended(NotInRoles="PeskyUser")]
[HttpPost]
[Route("api/Important/DoNotForgetToUpvote")]
public async Task<IHttpActionResult> DoNotForgetToUpvote()
{
return Ok("I did it!");
}
// В AuthorizeExtended equals Authorize
[AuthorizeExtended]
[HttpPost]
[Route("api/Important/DoNotForgetToUpvote")]
public async Task<IHttpActionResult> DoNotForgetToUpvote()
{
return Ok("I did it!");
}

Fluent NHibernate reference / many-to-one mapping cascade all not working

I have some problem with cascade all (orphan) and delete the old objcet from the database.
Example:
I have an class A which contains an object of class B. Now, when I create an object of class A and save it, everything works fine. When I call the method SetValueOfB(int i) and save the object A again, the old object B is still in the database.
Must the association between the classes always be directional (for every HasMany/Reference/HasOne...)? (But object b has nothing to know about object a)
Is there a way to solve the problem with unidirectional association?
Do I need a one-to-one mapping? Because the object B can only belong to object A (A is a parameter and B is a value).
Here is a failing test:
using System.Collections.Generic;
using System.Data;
using System.IO;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Mapping;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
using NUnit.Framework;
namespace ReferenceCascade.Test
{
public class CascadeTest
{
private const string DbFile = "firstProject.db";
[Test]
public void checkCascadeAll()
{
var sessionFactory = CreateSessionFactory();
A testee = new A(new B(1));
using (var session = sessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
session.SaveOrUpdate(testee);
transaction.Commit();
}
}
testee.SetValueOfB(2);
using (var session = sessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
session.SaveOrUpdate(testee);
transaction.Commit();
}
}
using (var session = sessionFactory.OpenSession())
{
using (session.BeginTransaction())
{
IList<B> stores = session.CreateCriteria(typeof(B))
.List<B>();
Assert.That(stores.Count, Is.EqualTo(1));
}
}
}
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(SQLiteConfiguration.Standard.UsingFile(DbFile).IsolationLevel(IsolationLevel.ReadCommitted))
.Mappings(m =>
m.FluentMappings.AddFromAssemblyOf<CascadeTest>())
.ExposeConfiguration(BuildSchema)
.BuildSessionFactory();
}
private static void BuildSchema(Configuration config)
{
// delete the existing db on each run
if (File.Exists(DbFile))
{
File.Delete(DbFile);
}
// this NHibernate tool takes a configuration (with mapping info in)
// and exports a database schema from it
new SchemaExport(config)
.Create(false, true);
}
}
public abstract class Entity
{
public const long InitialId = 0;
private readonly long _id;
protected Entity()
{
_id = InitialId;
}
public virtual long Id
{
get { return _id; }
}
}
public class A : Entity
{
private B _b;
public A()
{
}
public A(B b)
{
_b = b;
}
public virtual void SetValueOfB(int i)
{
_b = new B(i);
}
public virtual B B
{
get { return _b; }
}
}
public class B : Entity
{
private readonly int _i;
public B()
{
}
public B(int i)
{
_i = i;
}
public virtual int I
{
get { return _i; }
}
}
public class EntityMap<T> : ClassMap<T> where T : Entity
{
public EntityMap()
{
Id(x => x.Id).GeneratedBy.HiLo("33878").Access.CamelCaseField(Prefix.Underscore);
}
}
public class AMap : EntityMap<A>
{
public AMap()
{
Table("A");
References(x => x.B).Not.LazyLoad().Cascade.All().Access.CamelCaseField(Prefix.Underscore);
}
}
public class BMap : EntityMap<B>
{
public BMap()
{
Table("B");
Map(x => x.I).Not.LazyLoad().Access.CamelCaseField(Prefix.Underscore);
}
}
}
Or here is the project: vs project
We haven't found a way to solve the problem. In NHibernate version 4.1, the problem will be fixed and it is possible to use cascade=all-delete-orphan with many-to-one. See here: https://nhibernate.jira.com/browse/NH-1262

MvvmLight IDataService with async await

I'm trying to find a clean way to accomplish MvvmLight's IDataService pattern with async/await.
Originally I was using the callback Action method to work similar to the template's but that doesn't update the UI either.
public interface IDataService
{
void GetData(Action<DataItem, Exception> callback);
void GetLocationAsync(Action<Geoposition, Exception> callback);
}
public class DataService : IDataService
{
public void GetData(Action<DataItem, Exception> callback)
{
// Use this to connect to the actual data service
var item = new DataItem("Location App");
callback(item, null);
}
public async void GetLocationAsync(Action<Geoposition, Exception> callback)
{
Windows.Devices.Geolocation.Geolocator locator = new Windows.Devices.Geolocation.Geolocator();
var location = await locator.GetGeopositionAsync();
callback(location, null);
}
}
public class MainViewModel : ViewModelBase
{
private readonly IDataService _dataService;
private string _locationString = string.Empty;
public string LocationString
{
get
{
return _locationString;
}
set
{
if (_locationString == value)
{
return;
}
_locationString = value;
RaisePropertyChanged(LocationString);
}
}
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel(IDataService dataService)
{
_dataService = dataService;
_dataService.GetLocation(
(location, error) =>
{
LocationString = string.Format("({0}, {1})",
location.Coordinate.Latitude,
location.Coordinate.Longitude);
});
}
}
I'm trying to databind against gps coordinates but since the async fires and doesn't run on main thread it doesn't update the UI.
Might be unrelated, but AFAICT you're missing some quotes
RaisePropertyChanged(LocationString);
You pass the name of the property that changed, not its value.

Automapper - Map array of objects to one single object

I would like map array of objects to one single object.
For example:
public class ArrayData
{
//name of property in class MyObject in upper under score casing
public string PropName{get;set;}
//value of property in class MyObject
public string PropValue{get;set;}
}
Source data:
ArrayData [] sourceData = new ArrayData[]{new ArrayData{PropName="MY_ID",PropValue="1"}}
Destination object:
public class MyObject
{
public int MyId{get;set;}
}
My aim is set MyObject.MyId to 1.
Convention is:
if(ArrayData.PropName == MyObject.Property.Name)
{
MyObject.PropName = ArrayData.PropValue;
}
EDITED: I tried this way:
public class UpperUnderscoreNamingConvention : INamingConvention
{
#region Implementation of INamingConvention
public Regex SplittingExpression
{
get { throw new System.NotImplementedException(); }
}
public string SeparatorCharacter
{
get { return string.Format("_"); }
}
#endregion
}
public class TestProfile: Profile
{
public override string ProfileName { get { return "TestProfile"; } }
protected override void Configure()
{
SourceMemberNamingConvention = new UpperUnderscoreNamingConvention();
DestinationMemberNamingConvention = new PascalCaseNamingConvention();
CreateMap<ArrayData, MyObject>()
.ForMember(dest => dest.MyId, opt =>
{
opt.Condition(src => src.ColumnName == "MY_ID");
opt.MapFrom(src => src.Value);
});
}
}
Conversion:
Mapper.Initialize((obj) => obj.AddProfile(new TestProfile()));
var myClass = Mapper.Map<ArrayData[], MyClass>(sourceData);
It doesnt work, I get this exception:
AutoMapper.AutoMapperMappingException: Missing type map configuration
or unsupported mapping.
Also I think it is not good solution map all properties manualy:
.ForMember(dest => dest.MyId, opt => opt.Condition(src => src.ColumnName =="MY_ID"))

Resources