Laravel Excel 3.1 styling without model - php

I am using laravel-excel.com in my Laravel project.
Since data is not coming from a specific model, I didn't want to create a dummy model class and I generate the excel file directly:
return (new \Illuminate\Support\Collection($data))->downloadExcel(
'informe.xlsx',
null,
false
);
($data is a two-dimensional array with data of the unique data-sheet)
I wonder if there is any way to apply some style on columns (width, font-weight, etc.).
As far as I see it is possible ( like explained here) if I create a model for this excel.
Is it possible without?

It looks like it is impossible to apply styles on excel sheet without having a model.
However, I found a trick that makes it very easy to move my code to a model, I leave it here in case it might help somebody.
The idea is to pass $data array (which I retrieve using a service) as a parameter to the constructor:
Controller:
return Excel::download(new MyExport($data), "$fileName.xlsx");
app/Exports/MyExport.php:
<?php
namespace App\Exports;
use \Illuminate\Support\Collection;
class ActuacionesExport implements FromCollection
{
private $data;
function __construct($data) {
$this->data = $data;
}
public function collection()
{
return new Collection($this->data);
}
}
As you can see, the model does not do anything except of returning a Collection instance, but it permits adding styling, column width, drawings - whatever you need in your excel!

Related

Why do I have different dump in PHP and JSON?

I use Laravel Eloquent for my project. I get different object results with futher coding.
Php dump (var_dump(), dd(), dump()) object without unnecessary data, file json_encode spawns calculated data including loading something what was not required.
I have two model classes:
class Product extends Model
{
public function reviews()
{
return $this->hasMany(Review::class);
}
}
class Review extends Model
{
public function product()
{
return $this->belongsTo(Product::class);
}
}
To get a product I use
$product = App\Product::find(1)
But since I want to send data to JSON, I need to just load it by typing:
$product->reviews
But I don't want to load it, I just want to get additional calculated data without loading all reviews inside my json
$product['reviews_statistics'] = count($product->reviews);
I expect to find out how to set data for JSON without loading all $product->reviews
I would recomend You to try eagerloading the count:
$product = App\Product::withCount('reviews')->find(1)

How to override result of hasMany relationship?

Imagine I have a couple of simple objects like this:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function posts()
{
return $this->hasMany("App\Post");
}
}
class Post extends Model
{
public function user()
{
return $this->belongsTo("App\User");
}
}
We'll say the \App\Post object has an database column called jsondata which contains JSON-encoded data. When I want to display the user's posts in a view with that column decoded, I need to do this in the controller:
$posts = Auth::user()->posts()->get();
foreach ($posts as $post) {
$post->jsondata = json_decode($post->jsondata);
}
return view("user.show", ["posts"=>$posts]);
Is there a way to avoid that foreach loop in my controller and do the JSON decoding at a lower level?
I'm sure I could do this in App\User::posts() but that doesn't help other places where I need to display the decoded data. I tried defining App\Post::get() to override the parent method, but it doesn't work because hasMany() doesn't seem to return an instance of the model at all.
It can be done in different places/ways, but I would suggest to use an append for this property in your model if you want this data is always decoded everywhere and every time you retrieve a Post model, or simply a mutator.
see https://laravel.com/docs/master/eloquent-mutators
In your model you can define:
protected $appends = [
'name_of_property'
];
// calculated / mutated field
public function getNameOfPropertyAttribute()
{
return jsondecode($this->jsondata);
}
You then can always access this property with:
$post->name_of_property
Note the conversion from CamelCase to snake_case and the conversion from getNameOfPropertyAttribute > name_of_property. By default you need to respect this convention to get it working automagically.
You can substitute the name_of_property and NameOfProperty with what you want accordingly.
Cheers
Alessandro's answer seemed like the best one; it pointed me to the Laravel documentation on accessors and mutators. But, near the bottom of the page is an even easier method: attribute casting.
In typical Laravel fashion, they don't actually list all the types you can cast to, but they do mention being able to cast a JSON-formatted database column to an array. A little poking through the source and it turns out you can do the same with an object. So my answer, added to the App\Post controller, is this:
/**
* The attributes that should be casted to native types.
*
* #var array
*/
protected $casts = ["jsondata"=>"object"];
This automatically does the decode and makes the raw data available. As a bonus, it automatically does a JSON encode when saving!

Multiple tables in one model - Laravel

My Index page uses 3 tables in the database:
index_slider
index_feature
footer_boxes
I use one controller (IndexController.php) and call the three models like so:
public function index() {
return View::make('index')
->with('index_slider', IndexSlider::all())
->with('index_feature', IndexFeature::all())
->with('footer_boxes', FooterBoxes::all());
}
The three models above need ::all() data, so they are all setup like this:
class IndexSlider extends Eloquent {
public $table ='index_slider';
}
note: class name changes for each model
Seeing as my index page requires these 3 tables and the fact I am repeating the syntax in each model then should I be using polymorphic relations or setting this up differently? ORM from what I have read should have 1 model for each table, but I can't help but feel this would be silly in my situation and many others. DRY (don't repeat yourself) looses meaning in a sense.
What would be the best approach to take here or am I on the right track?
Firstly I should say each model is written for a specific table, you can't squeeze three tables into one model unless they are related. See Here
There are two ways I would go about making your code more DRY.
Instead of passing your data in a chain of withs I would pass it as the second parameter in your make:
public function index() {
$data = array(
'index_slider' => IndexSlider::all(),
'index_feature' => IndexFeature::all(),
'footer_boxes' => FooterBoxes::all(),
);
return View::make('index', $data);
}
Passing data as the second parameter. See here
The other way I would go about it, and this is a better solution if your application is going to grow large, is to create a service (another model class but not hooked up to eloquent) that when you call will return the necessary data. I would definitely do it this way if you are returning the above data in multiple views.
An example of using a service would look something like this:
<?php
// app/models/services/indexService.php
namespace Services;
use IndexSlider;
use IndexFeature;
use FooterBoxes;
class IndexService
{
public function indexData()
{
$data = array(
'index_slider' => IndexSlider::all(),
'index_feature' => IndexFeature::all(),
'footer_boxes' => FooterBoxes::all(),
);
return $data;
}
}
and your controller:
<?php
// app/controllers/IndexController.php
use Services/IndexService;
class IndexController extends BaseController
{
public function index() {
return View::make('index', with(new IndexService())->indexData());
}
}
This service can be expanded with a lot less specific methods and you should definitely change the naming (from IndexService and indexData to more specific class/method names).
If you want more information on using Services I wrote a cool article about it here
Hope this helps!

PHP: Should a Model in MVC be implemented as singleton? [duplicate]

This question already has answers here:
How should a model be structured in MVC? [closed]
(5 answers)
Closed 9 years ago.
In the ideal world one should not rely on singletons, the model in the controller and model inside the view would be 2 different instances. The problem arises when the controller sets a state and the view presentation depends on that state. For example:
class MyController extends Controller {
public function __construct(ModelUsers $cModel)
{
$this->model = $cModel;
}
public function action_Search($username) {
$this->model->filterByUsername($username);
}
}
class MyView extends View {
public function __construct(ModelUsers $vModel)
{
$this->model = $vModel;
}
public function users() {
return $this->model->getUsers();
}
}
How to share data between the controller model and the view model?
Starting from basics
A view requests from the model the information that it needs to generate an output representation to the user.
It means the view should be only responsible for showing the information. Just for that. You can also do some things like triming, chaning text size etc. but you shouldn't do some countings there or more complicated operations.
A model notifies its associated views and controllers when there has been a change in its state. This notification allows the views to produce updated output, and the controllers to change the available set of commands.
Model should be responsible for doing data operations. You can use it for example to get the records from database. It just be responsible for data handling.
A controller can send commands to its associated view to change the view's presentation of the model (e.g., by scrolling through a document). It can also send commands to the model to update the model's state (e.g., editing a document).
Controler is kind a proxy between model and view. You get there params and according to this params you set proper action of your controller. This action should create correct model object and use it to get data then assign to the view.
I've never used singleton in models. If you need some classes that would help MVC structure you can use helpers and as Hast suggested Registry pattern. I'm not a fan of using singleton.
You may also want to look at When to use singleton
So your question.
Controler -> model = Passing data via arguments of model's methods
Model -> controler = If reference then just work on it, if argument then do something and return result
Controler -> view = assign proper data to be viewed.
View->controller = go to special url to make data or use ajax request to retrieve it.
You can use Registry or Dependency injection instead.
Also in some cases you may pass some data to your view class as array. Like this:
class MyView extends View {
private $data = array();
public function __construct($data)
{
$this->data = $data;
}
public function users() {
return $this->data['model']->getUsers();
}
}
Of course you have to pass model when you caling the View class from your controller (or wherever you make call).

Custom filter for a field using ORM Model (result) in Kohana 3.2

I want to know if there's a way to filter the result from ORM. I wish to create a custom method to my Model, for example, one to filter the output from my Data Base. Right now, only is possible to filter the data from the POST in a form to save them into a Data Base, but, I want the opposite.
If I have one field on my table called "identification" with the value "8-985-256", I want that value as "08-0985-00256" (don't worry about how to add the extra zeros, that part is easy).
Let's say that I have a custom method on my Model called "format_identification".
Then, I get the data using the ORM class like so:
$user = ORM::factory('user', 1);
I want to echo the identification, but, with the correct format:
echo $user->format_identification();
This should print "08-0985-00256". If I use the name of the field, that works, but, the format of the value not.
I hope you understand what I'm trying to do.
Thank you for your time.
Add public method to your Model_User file called format_identification like:
<?php defined('SYSPATH') or die('No direct access allowed.');
class Model_User extends ORM {
public function format_identification() {
$identification_value = $this->identification;
// Add the extra zeros to value
return $identification_value;
}
}
I think there is a better way to solve your problem:
class Model_User extends ORM {
public function __get($column) {
if($column=='identification'){
// Do your stuff
}
return parent::__get($column);
}
}

Categories