I create alternative Id filed called alterId in database and use it in some cases instead of id field.
For example, on edit data client send alterId value instead of id...
Because it's part of a code that often repeats itself I extended Illuminate\Database\Eloquent\Model class with this class:
namespace App\NewModel;
use Illuminate\Database\Eloquent\Model;
class NewModel extends Model
{
public function __construct()
{
parent::__construct();
$this->attributes['alterId'] = $this->generateAlterId();
}
public static function convertIdToAlterId($alterId)
{
// some logic to convert if to alterId
}
public static function convertAlterIdToId($id)
{
// some logic to alterId to id
}
public function generateAlterId($tokenSize = 32)
{
// logic to generate alter id ftom time stamp or something like that...
}
}
that generate alterId automatically and has possibility of converting from one to the other.
My problem is when I try to seed some element with this extended model nothing happens, no errors and no inserted data in database.
For seeding I use this model
namespace App;
use Illuminate\Database\Eloquent\Model;
use \App\NewModel;
class TestModel extends NewModel
{
protected $fillable = ['name'];
protected $dates = ['created_at', 'updated_at'];
}
this simple factory:
use Faker\Generator as Faker;
$factory->define(App\TestModel::class, function (Faker $faker) {
return [
'name' => $faker->firstNameMale,
'created_at' => \Carbon\Carbon::now(),
'updated_at' => \Carbon\Carbon::now()
];
});
and seeder:
use Illuminate\Database\Seeder;
use \App\TestModel;
class TestModelsTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
//truncate
TestModel::truncate();
//create
factory(TestModel::class, 100)->create();
}
}
As I said before, nothing happens when I start the command
php artisan migrate:refresh --seed
even a error not showed. But if I change code and modify TestModel to inherits the Model instead of the NewModel then everything works fine, database get inserts!
What did I do wrong in this code?
I haven't tried to run your code, but I think you need to make it fillable:
protected $fillable = ['name','alterId'];
Related
I am currently updating a project from CakePHP 3 to CakePHP 4, and in this project I have a Trait that implements a "common" virtual property that some of the entities need.
<?php
namespace App\Model\Table;
use Cake\ORM\Table;
class NewsTable extends Table
{
public function initialize(array $config): void
{
parent::initialize($config);
$this->setTable('news');
$this->setPrimaryKey('id');
// more config here...
}
}
<?php
namespace App\Model\Entity;
use Cake\ORM\Entity;
class News extends Entity
{
use SitemapTrait;
protected $_virtual = ['sitemap']; // this is the virtual property that the trait should take care of
}
<?php
namespace App\Model\Entity;
use Cake\ORM\TableRegistry;
trait SitemapTrait
{
protected function _getSitemap()
{
$table = TableRegistry::getTableLocator()->get($this->getSource());
// more logic here...
}
}
The problem is that, on the _getSitemap() method, $this->getSource() returns a generic Cake\ORM\Table object, rather than a App\Model\Table\NewsTable object as I would expect, so everything that should happen afterward will not work.
I also wrote a simple command to check what happens when getSource() is called directly on an entity, and in this case I get the correct result, so the problem seems to be specifically related to it being called inside a Trait:
<?php
namespace App\Command;
use Cake\Command\Command;
use Cake\Console\ConsoleIo;
use Cake\Console\Arguments;
use Cake\ORM\TableRegistry;
class OrmTestCommand extends Command
{
protected $newsTable;
public function __construct()
{
$this->newsTable = TableRegistry::getTableLocator()->get('News');
}
public function execute(Arguments $args, ConsoleIo $io)
{
$news = $this->newsTable->find('all')
->first();
print_r($news->getSource());
}
}
In this case I correctly get a App\Model\Table\NewsTable object.
I don't get why this broke going from CakePHP 3.5.18 to 4.3.11. Do I need some extra config in my model? What am I doing missing or doing wrong?
I’m kind of new to Laravel and the whole API architecture, so my question may seem dumb at first.
My basic setup:
Laravel 8;
PHP 8;
routes\api.php
Route::post('/categories/',[ApiCategoriesInsertController::class, 'insertCategories'], function($insertCategoriesResults) {
return response()->json($insertCategoriesResults);
})->name('api.categories.insert');
\app\Http\Controllers\ApiCategoriesInsertController.php (created with php artisan make:controller)
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
// Custom models.
use App\Models\CategoriesInsert;
class ApiCategoriesInsertController extends Controller
{
private mixed $ciAPI;
public function __construct(Request $req)
{
}
public function insertCategories(Request $req): array
{
$this->ciAPI = new CategoriesInsert(['testing'=>'debug']);
return [‘status’ => ‘OK’];
}
}
\app\Models\CategoriesInsert.php (created with php artisan make:model)
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class CategoriesInsert extends Model
{
use HasFactory;
public function __construct(array $objParameters)
{
}
}
When I make a post to http://localhost:8000/api/categories, Laravel logs the following error:
local.ERROR: Too few arguments to function App\Models\CategoriesInsert::__construct(), 0 passed in … Too few arguments to function App\\Models\\CategoriesInsert::__construct(), 0 passed in …
Anyone knows what’s wrong or missing in my architecture?
Thanks!
Make your model's constructor compatible with parent.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class CategoriesInsert extends Model
{
use HasFactory;
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
}
}
Also, notice, that when you call new CategoriesInsert(['testing'=>'debug']), you do not save the data in your database. Use:
$insert = new CategoriesInsert(['testing'=>'debug']);
$insert->save();
Or:
CategoriesInsert::create(['testing'=>'debug']);
you don't need to pass data to model
change your code to bellow code:
public function insertCategories(Request $req): array
{
CategoriesInsert::create(['testing' => 'debug']);
return [‘status’ => ‘OK’];
}
key of passed array is your filed name in database, and value stored data
also you should define fillable parameter in model
protected $fillable = [
'title',
'slug',
'priority',
];
What's wrong with my code, I tried to export my data table using framework Laravel. The file is downloaded with empty content.
StockModel.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Stock extends Model {
protected $table = 'stock_tb';
protected $primaryKey = 'id';
protected $fillable = ['stock_id', 'input_date', 'quantity'];
}
AdminController.php
use Excel;
use App\Stock;
use App\Exports\StockExport;
class adminController extends Controller {
public function __construct() { }
public function printStockReport(){
return Excel::download(new StockExport('07/01/2020'), 'ado.xlsx');
}
StockExport.php
namespace App\Exports;
use App\Stock;
use Maatwebsite\Excel\Concerns\FromQuery;
class StockExport implements FromQuery
{
protected $id;
public function __construct($date_var)
{
$this->date = $date_var;
}
public function query()
{
return Stock::query()->where('input_date', $this->date)->get();
}
}
Router
Route::get('admin/printStockReport', 'adminController#printStockReport');
Fyi: I run the SQL code on my RDBMS with criteria input date 07/01/2020. It returns 129 records.
Thank you
remove ->get() , according to laravel-excel documentation no need to that.
I am trying to simply save a model to the database via a controller without setting the fields directly but instead having them set in the constructor of said object.
Here is the class handling the logic. If the commented out line
//$todoItem->item = $todo; is uncommented, it works fine and saves whatever is entered in $todo in the database. However, I would like to set that value in the constructor of the task object and not need to manually specify it. I found this question: Laravel with Eloquent doesn't save model properties on database suggesting I could set the property as protected and have it work, but that still does not.
NewTodo.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class NewTodo extends Controller
{
public function saveTodoItem(Request $request)
{
$todo = $request->input('content');
$todoItem = new \App\Task($todo);
//$todoItem->item = $todo;
$todoItem->save();
return view('testview', ['name' => $todoItem->getItem()]);
}
}
Task.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Task extends Model
{
protected $item = null;
function __construct($newItem)
{
$this->item = $newItem;
}
function getItem()
{
return $this->item;
}
}
Summary, database entry being stored as blank unless $todo->item is manually set when from what I can $todo->item is being set in the constructor.
You don't need to specify these in the constructor. You can use Mass Assignment
Model:
class Task extends Model
{
protected $fillable = ['item'];
}
Controller:
class NewTodo extends Controller
{
public function saveTodoItem(Request $request)
{
$todo = $request->input('content');
$todoItem = new \App\Task::create(['item' => $todo]);
return view('testview', ['name' => $todoItem->getItem()]);
}
}
I have got following issue during seed data in laravel framework.
php artisan db:seed --class=LevelsTableSeeder
[Illuminate\Database\Eloquent\MassAssignmentException]
level
My seed file(LevelsTableSeeder.php) as follows.
<?php
use App\Models\Levels;
use Illuminate\Database\Seeder;
class LevelsTableSeeder extends Seeder {
public function run()
{
$levels = [
['level'=>1, 'xp_second'=>0.101, 'xp_hour'=>365.220],
['level'=>2, 'xp_second'=>0.104, 'xp_hour'=>365.220]
];
foreach($levels as $level) {
Levels::create($level);
}
$this->command->info('Levels seeded :-)');
}
}
And my Levels model file as follows:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Cache;
class Levels extends Model {
protected $table = 'levels';
public function maxLevel()
{
return Cache::get('levels_max_level', function() {
return parent::max('level');
});
}
}
Could you help me?
Regards.
The MassAssignmentException is thrown whenever you try to assign multiple fields in a Model and then create it in a database. In order to protect your database, the Eloquent library offers you the Mass Assignment Protection, which means only fields you allow to be mass assigned will be accepted.
Laravel 5.2 Documentation for Eloquent
Add to your Model the attribute protected $fillable with an array of fields you are interested in mass assigning:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Cache;
class Levels extends Model {
protected $table = 'levels';
protected $fillable = ['level', 'xp_second', 'xp_hour'];
public function maxLevel()
{
return Cache::get('levels_max_level', function() {
return parent::max('level');
});
}
}
Another way to solve this issue is to unguard your model by calling Levels::unguard() from your Seeder Class. That way you will disable the Guard that protects your model from being mass assigned.
<?php
use App\Models\Levels;
use Illuminate\Database\Seeder;
class LevelsTableSeeder extends Seeder {
public function run()
{
Levels::unguard(); // to unguard your model
$levels = [
['level'=>1, 'xp_second'=>0.101, 'xp_hour'=>365.220],
['level'=>2, 'xp_second'=>0.104, 'xp_hour'=>365.220]
];
foreach($levels as $level) {
Levels::create($level);
}
$this->command->info('Levels seeded :-)');
Levels::guard(); // To guard back
}
}
This is an acceptable solution for seeding purposes, but not recommended on controller actions.
You should read the Laravel Docs, Laravel provides protection from Mass Assignment vulnerabilities and so you actually have to tell Laravel which fields are mass assignable inside your model, using the $fillable property:
class Levels extends Model {
protected $fillable = ['level', 'xp_second', 'xp_hour'];
}