Best way share data across all view in Laravel - laravel

I have some data that I want to share across all views. I am using AppServiceProvider's boot method to share data.it is working fine with MySQL however with pgsql when I run composer or PHP artisan commands I am getting the following error,(i do fresh and seed database very often)
SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "news" does not exist
it took me a while to understand where is the real issue. I m still unable to understand if it is pgsql related error or something else, bellow is code in AppServiceProvider. if I comment this code everything works fine except where I m using this.
public function boot()
{
$activeClubs = (new TournamentService())->getAllActiveClubs();
$activeNews = (new TournamentService())->getActiveNews();
$activeTournaments = (new TournamentService())->getActiveTournament();
View::share(['activeClubs' => $activeClubs, 'activeTournaments' => $activeTournaments, 'activeNews' => $activeNews]);
}
can you please help me that how can i share data across all views that i don't get this error in future.

you can determine if the app is running from console or not and prevent loading data in console
if ( !app()->runningInConsole() ){
// it's not console.
}
you mentioned you want to load this data in all views but sometimes, its one view that loaded in all of your views e.g. the layout.app view.
if its the case I recommend using view composers instead of View::share() as it will pass the data to that view before render and it will only run if that view is included in the page (so basically it will solve your problem even without app()->runningInConsole() condition required )
view composers doc
simple example:
View::composer('view-name', function ($view) {
$view->with('key', 'value');
});

Related

Two models, two fields, return preferred if present

Been struggling with how to do this the most optimized way possible...
I have two models: Catalog and Application.
Catalog has a field called name.
Application has a field called name.
Both have a relationship with each other.
I am struggling to find a way to create a function i could use across my Laravel application which i would pass application.id to it and it would return a $app->name value based on the following logic:
if $application->name exists, use this value as the $app->name for the $application object
otherwise, get the $catalog->name value and use it as the $app->name
Note that I would like to create a component #application() where i can simply pass the $application->id and build the display logic (theming/styling) into it.
Since i display this $app->name in many places, i would like to make it as lightweight as possible to avoid unnecessary queries.
I hope this makes sense! There are probably so many ways to go with it, i am lost at figuring out the way way to do this :(
I'm not completely sure to understand your model/DB design, but you could use a custom Helper to use that function through the whole app.
For that, you can create a simple PHP class Helper.php file in app/Http/Helpers folder or whatever location you want. Something like:
<?php
use App\Catalog;
use App\Application;
if (! function_exists('getAppName')) {
function getAppName($id){
// Do your logic here to return the name
$catalog = Catalog::find($id);
return $catalog->name;
}
}
?>
Then in any controller or view, you just do
getAppName($application->id)
Do no forget to add your helpers file to the composer autoload. So in composer.json in Laravel's root folder, add the helper path to the autoload array:
"files": [
"app/Http/Helpers/helpers.php"
],
Last but not least, run the following command:
composer dump-autoload
Please note that function logic is just for sample purposes since I don't know your model structure.
In my opinion, I care about the database cost.
Use ternary expression will be elegant. But it took two times IO costs from database if application name is empty.
$app_name = Application::find($id)->name;
$app_name = empty($app_name) ? Catalog::where('application_id', $id)->first()->name;
And this will more complicated, but the catalog_query only execute when application.name is empty, it execute in database and the result is taken out only once;
And Database will only find the name from one table or two table.
Something like this:
$catalog_query = Catalog::where('catalogs.application_id', $id)->select('catalogs.name')->groupBy('catalogs.name');
// if catalogs and applications relationship is 1:1, use ->limit(1) or remove groupBy('name') is better.
Application::where("applications.id", $id)
->selectRaw("IF(application.name IS NULL OR application.name = '', (" . $catalog_query->toSql() ."), applications.name ) AS app_name")
->mergeBindings($catalog_query->getQuery())
->first()
->app_name;
Hope this will help you.

Laravel Scout how refresh index with ElasticSearch?

I'm working on a Laravel project and I'm using https://laravel.com/docs/5.3/scout with ElasticSearch on a model Offer.
I already have some offers in my database, so I just run the command
`php artisan scout:import "App\Models\Offer"`
for generate the index for use my datas with ElasticSearch.
After that it's ok, I can search in my offers with, for example :
`$offers = Offer::search($request->keywords)->get();`
Now I have a function for create other offers in my database, and I dont know how can I refresh the index for use these new datas ?
In the documentation https://laravel.com/docs/5.3/scout#adding-records, I can read
all you need to do is save a model instance and it will automatically be added to your search index
I tried this and no, when I save() a new Offer, I can't find it in my index.
I tried to re run the command php artisan scout:import "App\Models\Offer" after add anew OFfer, but it's the same, I can't find it in my index.
Did I miss something ? Any ideas ?
Sorry for a late response on this but I ran into this issue myself when I attempted to use Scout. Everything went fine until I realized that the project's data would scale at a rate that went far beyond what scout could handle. In this case, however you can use the push() method instead of save(). I'm not sure why this isn't documented at all and it's rather frustrating but there's an answer at least.
So use:
->push()
instead of:
->save()
to update your indexes.
If that does not work for your specific version there is another way you can do it but it is "slightly" redundant. It involves a mix of using the queue system with the Artisan system and a command. In this you:
Create a queue/job php artisan make:job JobNameHere (As of Laravel 5.2 - 5.4)
Add use Artisan; to the top of that newly created Job Class so you can pull in the Artisan's functionality
In the handle of that Job Class add
class JobNameHere implements ShouldQueue {
...
...
public function handle() {
Artisan::call('scout:import', ['name' => "App\YourModelNameHere"]);
}
}
Add a dispatch call to that job class right after your DB push() process is called.
Example:
class YourController extends Controller {
public function yourUpdateMethod(Request $request) {
//Some code you wrote
//Some more code you wrote
$update_obj->push( $array_to_update_obj);
dispatch(new JobNameHere());
}
}
Test your index by searching on it
If all went well then you should no longer get any errors. Please leave a comment and let me know how it went... provided you're still having this issue.
I would also like to mention that Laravel Scout does not support ElasticSearch anymore as of August of 2016 (I believe). No one really knows why the support was removed but there are a few tutorials out there to help you get Laravel and Elastic search working together again.
I will also note, based on my research, that if your project is small then you should be fine to use Scout and not need to use ElasticSearch. If your project is going to get huge, then you're probably better off finding a package that supports and well documents how handle Laravel's relationships between models. Elastic search is capable of accomplishing this but there are tons of docs that make figuring it out difficult. Here are some semi-decent tutorials to help get you going down the right path.
https://tirdeamihai.com/blog/laravel-and-elasticsearch
https://laravel-news.com/laravel-and-elasticsearch
Plastic is a package that I would currently recommend as it's being actively worked on. Elasticquent hasn't been touched or updated since last year in June.
https://github.com/sleimanx2/plastic#1---create-a-new-index

Laravel created_by/modified_by relations

I was trying to get this working in a typical belongsTo relation. However it keeps saying that the column is not set in the model, even if looking in the actual database it is there.
I have tried to look at the source code as well as try many approaches to bypass this issue, however nothing seems to do anything.
public function modifiedBy()
{
return $this->belongsTo('\Modules\Users\Model\User', 'modified_by');
}
public function createdBy()
{
return $this->belongsTo('\Modules\Users\Model\User', 'created_by');
}
This is the code inside the model, I use PSR-0 to define modules, better splitting up logic (no issues with that) but using this it would give an error of
Undefined property: \Modules\Module\Model\CurrentModel::$modified_by
This is coming from a seed to push some initial info into the database.
$user = Sentinel::findById(1);
$model = new CurrentModel;
$model->modifiedBy()->associate($user);
$model->save();
This is basically how it goes together, I have tried for some time to figure out what is wrong but I am calling blanks. Any ideas?
Found out a solution. Not a fix though but I would consider this an issue with laravel so I may look into adding it as a bug report (although this could be fixed in laravel 5?).
Basically with modified_by I need to define the column it is using and not let laravel automatically generate it (in order to do this "cleanly"). However the "bug" (only calling it a bug as currently I can only see this as an unintended problem) makes it so you cannot define the column it will be using, you have to let laravel decide it for you.
So I changed the functions to look like this:
public function modifiedby()
{
return $this->belongsTo('\Modules\Users\Model\User');
}
This makes laravel assume the column is modifiedby_id, but by changing my migrations to reflect that there was no more error.

Sentry & Laravel, getting users within a group. changing findAllUsersWithAccess to have pagination

I'm trying to find all users w/ a specific permissions list in Sentry with laravel. The problem is that Sentry::findAllUsersWithAccess() returns an array().
as stated in their github repository i pinpointed their code to be
public function findAllWithAccess($permissions)
{
return array_filter($this->findAll(), function($user) use ($permissions)
{
return $user->hasAccess($permissions);
});
}
right now, it gets all users and filter it out with users with permission list. the big problem would be when I as a developer would get the set of users, it'll show ALL users, i'm developing an app which may hold thousands of users and i only need to get users with sepcific permission lists.
With regards to that would love to use one with a ->paginate() capability.
Any thoughts how to get it without getting all the users.
Why dont you override the findAllWithAccess() method and write your own implementation, which uses mysql where instead of array_filter().
I dont know your project structure and the underlying db schema, so all i can give you atm is the link to the eloquent documentation Querying Relations (whereHas).
In case you dont know where to start: its always a good idea to look at the ServiceProvider (SentryServiceProvider, where the UserProvider, which holds the findAllWidthAccess() method, is registered). Override the registerUserProvider method and return your own implementation of the UserProvider (with the edited findAllWithAccess() method).
Hope that will point you in the right direction.
In Laravel you can do pagination manually on arrays:
$paginator = Paginator::make($items, $totalItems, $perPage);
Check the docs: http://laravel.com/docs/pagination

Output caching in codeigniter displays blank page

I've read a lot of discussions about this but have no luck.
I have a controller:
function get_list() {
$data['promoname'] = $this->Default_model->get_promo($this->input->post('year'));
$this->output->cache(10);
// Render view
$this->layout->render(get_platform().'/promo/promo_view', $data);
}
And in my Default_model:
function get_promo($year = NULL) {
$this->db->cache_on();
//query here
}
When the page is loaded for the first time, the data is displayed perfectly. But when I tried to load it again to check if it is cached it displays nothing, a blank white page. Error reporting is enabled.
A file has been created under application/cache, meaning there is no permission issue. But the file created contains '1357184142TS--->'.
Tried to remove the $this->db->cache_on(), but the behavior is still the same. What seems to be the problem?
Check your view file to see if any tags are missed or any values getting interrupted in-between.
As documentation https://ellislab.com/codeigniter/user-guide/general/caching.html says:
Because of the way CodeIgniter stores content for output, caching will only work if you are generating display for your controller with a view.
so you have to call:
$this->load->view(get_platform().'/promo/promo_view', $data)
instead of
$this->layout->render(get_platform().'/promo/promo_view', $data);
I am having a same problem. I haven't properly tested it though. I think the blank page is caused by using ($this->db->last_query()) in the Code with Nested Queries.
Try changing the $db['default']['db_debug'] = TRUE; to false. It may resolve the problem if other system queries are not running.

Resources