In laravel there are some config files which could be controlled / set with .env file for developing. My question is it possible to set the production values through a db table for example a settings_mail and settings_app table. I need this so that the admin when nessesery could change Some value in a view and doesn't need entering the code
Create a settings table, like this:
name
value
category
hostname
smpt.example.com
mail
address
San José
general
Create a setting model based in table structure:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Setting extends Model
{
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'settings';
protected $name = '';
protected $value = '';
protected $category = '';
}
Load the settings to be accessible at entire application:
// app/Providers/AppServiceProvider.php
public function boot(){
$settings = App\Setting::lists('name', 'value')->all();
config()->set('settings', $settings);
}
Now, get some config:
$address = config('settings.address');
Related
So i create a column with
$table->enum('role', ['admin', 'customer'])->default('customer');
and i want a table with
if email with #domain.com then assign into role admin
else go to customer.
is there a way to do this in migration? or do i need to set up in model?
i'm a beginner in php and Laravel so please give me detailed instruction.
I invite you to create an observer on your Eloquent model.
You can read the doc at: https://laravel.com/docs/9.x/eloquent#observers
Remember to create a PHP enum to check your roles. This will allow you to more easily add roles or do additional checks in your code without having magic values:
<?php
enum Role : string
{
case ADMIN = 'admin';
case CUSTOMER = 'customer';
}
The creating event seems to be the most suitable since it will be observed during insertion :
<?php
namespace App\Observers;
use App\Models\User;
class UserObserver
{
/**
* Handle the User "creating" event.
*
* #param \App\Models\User $user
* #return void
*/
public function creating(User $user)
{
// Your logic here
if(str_ends_with($user->email, '#domain.com')) {
$user->role = Role::ADMIN->value;
} else {
$user->role = Role::CUSTOMER->value;
}
}
}
In Laravel I need to communicate to a 3rd party API. Thay have given me some PHP implementation (class) which I can use to connect and communicate with their API.
But when I try this as a class in a subfolder of the App folder and add this to my controller, I get a class not found error.
I have added a folder 'Qenner' (the provider of the API) in the App folder. And copied their classes in there.
In my controller I'm using these classes and add a code sample, like they send it to me.
Controller code (API-KEY is replaced with the actual key):
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Qenner\Search;
use QennerSearch\ServiceClient;
class TestController extends Controller
{
public function index() {
$search = new Search('https://search.qenner.com', 'API-KEY', true, 'nl-NL');
$response = $search->getCriteria([], ['Country'], []);
if (!$response->isError()) {
$criterionSets = $response->getCriterionSets();
$countryCriterionSet = criterionSets[0];
$countries = $countryCriterionSet->getCriteria();
$resultCount = $response->getResultCount();
}
dd($response);
}
Search.php in Qenner folder:
/**
* #file
* Contains QennerSearch\Search.
*/
namespace QennerSearch;
use QennerSearch\model\messages\CriterionTypesResponse;
use QennerSearch\model\messages\CriteriaRequest;
use QennerSearch\model\messages\CriteriaResponse;
use QennerSearch\model\messages\ErrorResponse;
use QennerSearch\model\messages\SearchRequest;
use QennerSearch\model\messages\SearchResponse;
use QennerSearch\model\messages\PriceRequest;
use QennerSearch\model\messages\PriceResponse;
use QennerSearch\model\messages\AccommodationInfoRequest;
use QennerSearch\model\messages\AccommodationInfoResponse;
use QennerSearch\model\messages\AutoCompleteRequest;
use QennerSearch\model\messages\AutoCompleteResponse;
/**
* Class Search, using ServiceClient to communicate, implementing the SearchInterface
*
* #package QennerSearch
*/
class Search extends ServiceClient implements SearchInterface {
.....
The folder has a ServiceClient.php
ServiceClient.php
/**
* #file
* Contains QennerSearch\Search.
*/
namespace QennerSearch;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
/**
* Class Search.
*
* #package QennerSearch
*/
class ServiceClient {
protected $http_client = null;
protected $engine_url = null;
protected $api_key = null;
protected $log_calls = false;
protected $locale = null;
protected $last_result_code = 0;
protected $last_error_body = null;
public function __construct($engine_url, $api_key, $log_calls = false, $locale = "nl-NL") {
$this->http_client = new Client();
$this->engine_url = $engine_url;
$this->api_key = $api_key;
$this->log_calls = $log_calls;
$this->locale = $locale;
I get this error:
Class 'QennerSearch\ServiceClient' not found
While I expected a dump of the output
Updated
After seeing your folder structure in the comments, I believe ServiceClient.php and Search.php, both are inside the folder: app\Qenner, hence inside those files:
wherever you are using: namespace QennerSearch;
you should use: namespace App\Qenner;
and then inside your controller, instead of using: use QennerSearch\ServiceClient;
use: namespace App\Qenner\ServiceClient
Namespaces are not like aliases, they need to reflect the position of the file itself if that makes sense.
Please give it a try and let me know if it works.
So I have a Page Model, which extends the Eloquent Model class. I am trying to override the constructor, where I need some additional logic. This is what I currently have:
class Page extends Model
{
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
$this->main_image = null;
}
}
But this does not seem to save the main_image into the $this->attributes property when I call Page::find(1);.
I believe this is because Page::find eventually calls Model::newFromBuilder, which looks like this:
public function newFromBuilder($attributes = [], $connection = null)
{
$model = $this->newInstance([], true);
$model->setRawAttributes((array) $attributes, true);
$model->setConnection($connection ?: $this->getConnectionName());
return $model;
}
So as you can see it creates the instance first and then sets the attributes, which means that anything set in the constructor gets ignored.
Is there any workaround for this to be able to override constructor (or similar method) to change the attributes for every retrieved/created model instance? Obviously I could override the newFromBuilder, newInstance, __construct and similar methods, but this seems very hacky and unmaintainable.
Thanks!
If all you need is to be able automatically modify a model's attribute when retrieved or set, then use Laravel Eloquent's Accesors and Mutators:
Defining An Accessor
To define an accessor, create a getFooAttribute method on your model where Foo is the "studly" cased name of the column you wish to access. In this example, we'll define an accessor for the first_name attribute. The accessor will automatically be called by Eloquent when attempting to retrieve the value of the first_name attribute:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get the user's first name.
*
* #param string $value
* #return string
*/
public function getFirstNameAttribute($value)
{
return ucfirst($value);
}
}
As you can see, the original value of the column is passed to the accessor, allowing you to manipulate and return the value. To access the value of the accessor, you may simply access the first_name attribute on a model instance:
$user = App\User::find(1);
$firstName = $user->first_name;
Defining A Mutator
To define a mutator, define a setFooAttribute method on your model where Foo is the "studly" cased name of the column you wish to access. So, again, let's define a mutator for the first_name attribute. This mutator will be automatically called when we attempt to set the value of the first_name attribute on the model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Set the user's first name.
*
* #param string $value
* #return void
*/
public function setFirstNameAttribute($value)
{
$this->attributes['first_name'] = strtolower($value);
}
}
The mutator will receive the value that is being set on the attribute, allowing you to manipulate the value and set the manipulated value on the Eloquent model's internal $attributes property. So, for example, if we attempt to set the first_name attribute to Sally:
$user = App\User::find(1);
$user->first_name = 'Sally';
In this example, the setFirstNameAttribute function will be called with the value Sally. The mutator will then apply the strtolower function to the name and set its resulting value in the internal $attributes array.
I've started to use Voyager and I've problems with a controller.
I've create a new table in database called Progress, voyager by default create a BREAD form to browse read delete and add items .
I like to put a default value into a field when the user go to add a new item. The default value that I like to put is authentication user_id
How can I do that?
Thanks.
You can do that completely outside of Voyager.
First exclude the authentication_user_id from the Add form (in Voyager's database interface). If the field doesn't take a null value you can set some temporary default, or modify your migrations - whichever is most convenient.
Next create a model observer and then utilise the created() function. For example:
<?php
namespace App\Observers;
use App\Models\Project;
class ProgressObserver
{
/**
* Listen to the Progress created event.
*
* #param Progress $progress
* #return void
*/
public function created(Progress $progress)
{
$progress->authentication_user_id = WHATEVER_YOU_DO_HERE;
$progress->save();
}
}
You can do that by creating a model for your bread, as shown in image
after you have done creating a model for your bread you can create a function named save
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use TCG\Voyager\Traits\Translatable;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use Auth;
class MyViewModel extends Model
{
//
protected $table = "my_view";
public function save(array $options = [])
{
$this->user_id = \Auth::user()->id;
parent::save();
}
}
now whenever you save any record in administration of voyager, you will see current login user id is getting saved in your database table.
I think you can create a migration to write a default value for that field
You have to add following code into the model like this,
//assign created_by loggedin user
public function __construct(array $attributes = [])
{
$this->creating([$this, 'onCreating']);
parent::__construct($attributes);
}
public function onCreating($row)
{
// Placeholder for catching any exceptions
if (!\Auth::user()->id) {
return false;
}
$row->setAttribute('created_by', \Auth::user()->id);
$row->setAttribute('assign_to', \Auth::user()->id);
}
i have adding this because of my project need this. you can also add your field in onCreating() function.
I am trying to assign a value to $table property in my Model, based on the URL string. There I am getting "Array to string conversion" error. Below are code level details. Can someone please help? Thanks.
I have coded my model __constructor() as shown below.
<?php
use Illuminate\Auth\UserTrait;
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\Reminders\RemindableInterface;
class Disaster extends Eloquent {
use UserTrait,
RemindableTrait;
/**
* The database table used by the model.
*
* #var string
*/
protected $table;
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array('password', 'remember_token');
public function __construct($disasterArea, $disaster = "flood") {
$this->table = $disasterArea . '_' . $disaster;
}
}
I am trying to pass required values while Model instantiation from my controller as shown below.
class DisasterController extends \BaseController {
public function getFloodTweets($floodArea){
$flood = new Disaster($floodArea, "floods");
$floodTweets = $flood->orderBy('created_at','desc')->groupBy('tweets')->paginate(10);
$floodAreaUc = ucfirst($floodArea);
return View::make("disaster.floodTweets",['title'=>"$floodAreaUc Flood",'floodTweets'=>$floodTweets,'floodArea'=>$floodAreaUc]);
}
}
}
that means if I trigger an URL like www.example.com/floods/city my model should build the table as 'city_floods' which is the naming convention we are following.
And also, I observed table name is being build correctly but throwing this error. And strange thing is my code works fine when I hard code this table name. i.e.
$this->table = "city_floods" works fine but
$this->table = $disasterArea . '_' . $disaster do not. I don't understand what is the difference. Can someone please suggest where I am doing wrong.
I working on UBUNTU 14.04 with Laravel 4.2 framework.
Edit
Well You cannot pass the data in that way to the eloquent model because the original abstract eloquent model have the first parameter as array! and it will try to put it in this way.
EDIT
As you can see on your screen shot - the model is resolving somewhere with a newInstance method what means that it trying to put (propably) an empty array into you string varible.
The solution
The best option is to split the logic into few Disaster Models that extends the main Disaster model and resolving them from factory like that:
class UsaFloodDisaster extends Disaster
{
protected $table = 'usa_flood';
}
class FranceFloodDisaster extends Disaster
{
protected $table = 'france_flood';
}
(...)
class DisasterFactory
{
public function make($area, $disaster = 'flood')
{
$className = ucfirst(camel_case($area.'_'.$disaster));
return app($className);
}
}
then your controller would looks like:
class DisasterController extends \BaseController {
public function getFloodTweets($floodArea){
$flood = app(DisasterFactory::class)->make($floodArea, "floods");
$floodTweets = $flood->orderBy('created_at','desc')->groupBy('tweets')->paginate(10);
$floodAreaUc = ucfirst($floodArea);
return View::make("disaster.floodTweets",['title'=>"$floodAreaUc Flood",'floodTweets'=>$floodTweets,'floodArea'=>$floodAreaUc]);
}
}