In my application I have many Controllers like CashInController, CashOutController, InvoiceController etc. For each of them I have created separated Repository in my App\Repository\ folder.
Sometimes I need same functions or Queries for many Controllers. As an example:
public function months()
{
return [
'January' => 'January',
'February' => 'February',
'March' => 'March',
'April' => 'April',
'May' => 'May',
'June' => 'June',
'July' => 'July',
'August' => 'August',
'September' => 'September',
'October' => 'October',
'November' => 'November',
'December' => 'December'
];
}
public function clients()
{
return Client::all()->lists('name','name')->sort();
}
Now, I want to create a common repository for every controllers or global functions which I can use everywhere in my application.
Preferably, if you have chunk of codes that needs to be repeated in several controllers, better to add it to a Job.
To Use Jobs.
First add a job:
php artisan make:job TestJob
You will find a new class created under App\Jobs, add your code in the handle method:
<?php
namespace App\Jobs;
use App\Jobs\Job;
use Illuminate\Contracts\Bus\SelfHandling;
class TestJob extends Job implements SelfHandling
{
/**
* Create a new job instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
//
}
}
Then in any class, add the following trait, Controllers have that trait by default:
use DispatchesJobs;
Wherever you need to dispatch the job, run that code:
$this->dispatch(new TestJob());
To Use Helper functions.
For simple functions, you can create Helper classes, to do that create Helper directory under App, then create a new class:
<?php
class MyHelper
{
public static function test()
{
return "hello";
}
}
Add the class to your composer autoload, in your composer.json:
"autoload": {
"classmap": [
"database",
"app/Helpers/MyHelper.php"
Then in your classes do the following:
MyHelper::test();
Related
Hello I am using Laravel-activitylog and when i tried to add the train to Model it gives me this error
Class App\Models\Setting contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (App\Models\Setting::getActivitylogOptions)
and this is all my Model code
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Astrotomic\Translatable\Translatable;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Astrotomic\Translatable\Contracts\Translatable as TranslatableContract;
use Spatie\Activitylog\Traits\LogsActivity;
class Setting extends Model
{
use Translatable,SoftDeletes;
use LogsActivity;
public $translatedAttributes = ['name', 'slogan', 'description', 'summary', 'address'];
protected $fillable = ['id', 'logo', 'favicon', 'phone', 'email', 'facebook', 'twitter', 'instagram', 'created_at', 'updated_at'];
// protected static $logAttributes = ['name', 'logo'];
public static function check()
{
$setting = Self::all();
if(count($setting)<1)
{
$arrayName = array();
$arrayName['id']= 1;
foreach(config("app.languages") as $key => $language)
{
$arrayName[$key]['name'] = $language;
$arrayName[$key]['description'] = $language;
}
Self::create($arrayName);
}
return $setting = Self::where('id','1')->first();
}
}
It looks like you are using version 4 of laravel-activitylog, in that case you should add:
use Spatie\Activitylog\LogOptions;
And the getActivitylogOptions() method, for example:
public function getActivitylogOptions()
{
return LogOptions::defaults()
-> logOnly(['text'])
-> logOnlyDirty()
-> dontSubmitEmptyLogs();
}
If you are using PHP 8 do not forget to also declare the return type:
public function getActivitylogOptions(): LogOptions
{
return LogOptions::defaults();
}
More info here: https://spatie.be/docs/laravel-activitylog/v4/advanced-usage/logging-model-events
For the format you are using in your code to work, you can also use the previous version, indicating in composer:
"spatie/laravel-activitylog": "^3", and following this documentation: https://spatie.be/docs/laravel-activitylog/v3/introduction
I wonder what is the difference between this two methods in a Module Class : fetch and display.
Looking at the source code of different modules I see fetch with renderWidget and display with traditionnal hooks.
class MyModule extends Module {
//...
public function hookdisplayTopColumn($params)
{
$this->context->smarty->assign(array(
'foo' => 'bar',
));
return $this->display(__FILE__, 'html.tpl');
}
//...
public function renderWidget($hookName, array $configuration) {
if (!$this->isCached($this->templateFile, $this->getCacheId('blockreassurance'))) {
$this->context->smarty->assign($this->getWidgetVariables($hookName, $configuration));
}
return $this->fetch($this->templateFile, $this->getCacheId('blockreassurance'));
}
}
thank you and good evening !!
I am developing a web application using Laravel 8. I have noticed that quite a lot of things have changed in Laravel 8 including factories.
I have a factory class MenuCategoryFactory for my MenuCategory model class with the following definition.
<?php
namespace Database\Factories;
use App\Models\Menu;
use App\Models\MenuCategory;
use Illuminate\Database\Eloquent\Factories\Factory;
class MenuCategoryFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = MenuCategory::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'name' => $this->faker->name,
'menu_id' => Menu::factory()->create(),
];
}
}
In my code (database seeder class), I am trying to override the menu_id as follow while I am creating the factories.
$restaurant = Restaurant::first();
MenuCategory::factory()->create([
'menu_id' => $restaurant->menu->id
]);
But it is not using the value I passed, $restaurant->menu->id. Instead, it is creating a new menu. What is wrong missing in my code and how can I fix it?
In your factory definition, don't call ->create(), instead set it up like this:
public function definition()
{
return [
'name' => $this->faker->name,
'menu_id' => Menu::factory(),
];
}
Then you you should be able to set up related models (assuming you the relationships setup in the model) like this:
$restaurant = Restaurant::first();
MenuCategory::factory()->for($restaurant)->create();
Change the definition to
public function definition()
{
return [
'name' => $this->faker->name,
'menu_id' => function() {
Menu::factory()->create()->id,
}
];
}
then you can replace the value
My sql code is :
SELECT b.item_id as breakfast,l.item_id as lunch, d.item_id as dinner
FROM breakfast_menus as b,lunch_menus as l,dinner_menus as d
where (b.day_id=3 and l.day_id=3 and d.day_id=3)
my models are:
breakfast_id model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class breakfast_item extends Model
{
protected $fillable = [
'id', 'item'
];
}
breakfast_menu model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class breakfast_menu extends Model
{
protected $fillable = [
'day_id', 'item_id'
];
public function item()
{
return $this->belongsTo('App\breakfast_item', 'item_id');
}
public function day()
{
return $this->belongsTo('App\day', 'day_id');
}
}
day model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class day extends Model
{
protected $fillable = [
'day',
];
public function breakfast_menu()
{
return $this->hasOne('App\breakfast_menu', 'day_id');
}
}
and like this the rest models of lunch_items and lunch_menu,dinner_items and dinner_menu is declared. If required the models and relations can be changed. My main necessary is to show the data as a weekly view of breakfast ,lunch and dinner in a table
in your day Model, you have to define two relations:
public function lunch_menu()
{
return $this->hasOne('App\lunch_menu', 'day_id');
}
public function dinner_menu()
{
return $this->hasOne('App\dinner_menu', 'day_id');
}
then you load breakfast_menu,lunch_menu,dinner_menus for the day model where id for day =3
$value=day::find(3)->with(['breakfast_menu.item','lunch_menu.item',
'dinner_menus.item'])->get();
$value->breakfast_menu now is an object with an attribute called item witch has the 'id,item' field, you must check it out using debugger ....
for the literally converting you sql to ORM:
$values=Day:: addSelect([
'breakfast'=>breakfast_menu::select('breakfast_menus.item_id')
->where('breakfast_menus.item_id',3),
'lunch'=>lunch_menu::select('lunch_menus.item_id')
->where('lunch_menus.item_id',3),
'dinner'=>dinner_menu::select('dinner_menus.item_id')
->where('dinner_menus.item_id',3)
->get();
please note your original query doesn't get the items, but the item_id s
I have a class "performance", and to each performance other performances can be linked as recommendations. After some trial and error I have something semi-working, using the ORM:
public static $many_many = array(
'Recommendations' => 'Performance'
);
public static $belongs_many_many = array(
'Recommendations' => 'Performance'
);
The above lets me specify recommendations, but in normal many to manies (between two classes), the relation the other way around is also available. Here it is not. Any clue on how to make the inverse relation visible on the "Performance" class without creating the inverse many-to-many and manually inserting the inverse relation there?
Update(May 22, 2014): For now I've come to the conclusion that there isn't an out of the box solution to this problem. I made the following minimal example, based on #FinBoWa's solution, and that shows the "Inverse component of Degree.InterestingDegreesReversed not found (Degree)":
class Degree extends DataObject {
private static $db = array(
"Name" => "Varchar(255)",
);
private static $many_many = array(
'InterestingDegrees' => 'Degree'
);
private static $belongs_many_many = array(
'InterestingDegreesReversed' => 'Degree.InterestingDegrees'
);
}
class DegreeAdmin extends ModelAdmin {
public static $managed_models = array('Degree');
static $url_segment = 'degrees';
static $menu_title = 'Degrees';
}
I also tried #g4b0's solution, but that has the serious drawback that it does not show the reverse relationship in the admin. For now I am using his solution, but it is not a real solution to the problem. Therefore I will not accept an answer for now...
You have to specify two different names for many_many and belongs_many_many, so you can access them. For example:
public static $many_many = array(
'RelatedRecommendations' => 'Performance'
);
public static $belongs_many_many = array(
'Recommendations' => 'Performance'
);
You should be able to use the dot notation in the relations.
One of our projects had degrees and we wanted to relate the interesting degrees using the same class:
private static $many_many = array(
'InterestingDegrees' => 'Degree'
);
private static $belongs_many_many = array(
'InterestingDegreesReversed' => 'Degree.InterestingDegrees'
);
This works if you add the editor manually when relating site trees.
But if you use model admin, you have to declare the fields manually otherwise you will get erros. So a working example if you are using model admin would be:
class Degree extends DataObject {
private static $db = array(
"Name" => "Varchar(255)",
);
private static $many_many = array(
'InterestingDegrees' => 'Degree'
);
private static $belongs_many_many = array(
'InterestingDegreesReversed' => 'Degree.InterestingDegrees'
);
public function getCMSFields() {
$fields = new FieldList();
$fields->add(new TextField("Name"));
// dont show the field untill we have something to relate to
if($this->ID){
//Interesting degrees
$gfc = GridFieldConfig_RelationEditor::create();
//Remove add and edit features
$gfc->removeComponentsByType('GridFieldAddNewButton');
$gfc->removeComponentsByType('GridFieldEditButton');
$gf = new GridField('InterestingDegrees', null, $this->InterestingDegrees(), $gfc);
$fields->add($gf);
}
return $fields;
}
}
class DegreeAdmin extends ModelAdmin {
public static $managed_models = array('Degree');
static $url_segment = 'degrees';
static $menu_title = 'Degrees';
}
I've gone through both ideas, and this is what I've come up with for a project I'm working on (I'm using the Brand model).
This is inspired by both solutions, the only additional item I'm adding is the onAfterWrite method. There I'm just looping through all brands, and adding the other side.
This takes for all brands to be edited through only the Brands tab. The other should be removed in getCMSFields like this: $fields->removeByName('RelatedBrands');.
<?php
class Brand extends DataObject {
private static $many_many = [
'Brands' => 'Brand' //part 1 of brand-brand relation
];
private static $belongs_many_many = [
'RelatedBrands' => 'Brand' //part 2 of brand-brand relation
];
public function onAfterWrite() {
parent::onAfterWrite();
foreach ($this->Brands() as $brand) {
$this->RelatedBrands()->add($brand);
}
}
}