I'm building a Laravel Package.
I need to publish my custom migrations. One migration need another one to be run because it has a foreign key constraint.
In my service provider I'm doing this:
public function boot(Filesystem $filesystem)
{
$this->loadMigrationsFrom(dirname(__DIR__).'/migrations');
$this->publishMigrations($filesystem);
}
private function publishMigrations(Filesystem $filesystem)
{
if (! class_exists('CreateReferencedTable')) {
$this->publishes([
__DIR__ . '/../database/migrations/create_referenced_table.php.stub' => $this->getMigrationFileName($filesystem, 'referenced')
], 'migrations');
}
if (! class_exists('CreateExampleTable')) {
$this->publishes([
__DIR__ . '/../database/migrations/create_example_table.php.stub' => $this->getMigrationFileName($filesystem, 'example')
], 'migrations');
}
}
protected function getMigrationFileName(Filesystem $filesystem, string $table_name): string
{
$timestamp = date('Y_m_d_His');
return Collection::make($this->app->databasePath().DIRECTORY_SEPARATOR.'migrations'.DIRECTORY_SEPARATOR)
->flatMap(function ($path, $table_name) use ($filesystem) {
return $filesystem->glob($path.'*_create_'.$table_name.'_table.php');
})->push($this->app->databasePath()."/migrations/{$timestamp}_create_{$table_name}_table.php")
->first();
}
And then I run
php artisan vendor:publish --provider="FedericoArona\MyPackage\Providers\MyServiceProvider" --tag="migrations"
The problem is that the tables are being created with the exact same timestamp so they will be ordered by their name. This means that "Example" migration will be created before "Referenced" migration.
Obviously this means that when I run my migrations, they will fail because "Example" migration need to be run after "Referenced".
How can I solve? Thanks.
The only approach I've made work is a hack: adjust the timestamps. I put the number of migrations into a property in the provider
$this->migrationCount
and then decrement the timestamp (so if the tick counter increments in the middle of execution it still is different):
private function migratePath(string $file): string
{
$timeKludge = date('Y_m_d_His', time() - --$this->migrationCount);
return database_path(
'migrations/' . $timeKludge . "_$file.php"
);
}
It's not pretty but it works.
Related
My problem is that when I send a post from an rfid card via esp8266, the data is an rfid number, but the data can't appear because the code I gave has not been written into Laravel.
This PHP code :
<?php
if(isset($_POST['uid'])) {
$uid = $_POST["uid"];
$sql = mysqli_query($dbconnect, "INSERT INTO tb_entry VALUES ('$uid')");
}
?>
How can I write this code into Laravel controller?
it should be like this
if ($request->has('uid')) {
DB::table('tb_entry')->insert([
'uuid' => $request->uuid
]);
}
create a controller: php artisan make:controller MyController
add a method to the controller like public function test(Request $request) {}
rewrite your code a little bit and pasted in:
public function test(Request $request) {
if (null !== $request->post('uid')) {
$uid = $request->post('uid');
// Note: you can use Laravel model instead plain mysqli query
// ** Beware of SQL injection vulnerabilities! **
$sql = mysqli_query($dbconnect, "INSERT INTO tb_entry VALUES ('$uid')");
}
}
i have this function :
public function showProfile($id)
{
// Check if user already in redis with cache key user.1 for example
if (!Redis::exists('user.' . $id)) {
// If the user is not in redis, fetch it from DB and add it in redis for 60 seconds before returning it
$user = User::findOrFail($id);
Redis::set('user.' . $user->id, $user);
return $user;
} else {
// If user is in redis, just return it without querying the database
return Redis::get('user'.$id);// How to set this?
}
enter image description here
But the function return is null, why please...
It looks like your keys are different. You are setting user.id:
Redis::set('user.' . $user->id, $user);
And you are trying to get userid:
return Redis::get('user'.$id);
I am using Laravel-5.8 in my server. I have this external endpoint given to me which I cannot alter:
https://api.studklm.net/students/allstudents
It is a GET Request and in JSON (application/json) format.
[
{
"Student Code": "S001",
"Full Name": "Adeleke Omowale",
"StudentClass": "JSS 1",
"AcademicTerm": "First"
},
"Student Code": "S002",
"Full Name": "James Smith",
"StudentClass": "JSS 1",
"AcademicTerm": "First"
},
"Student Code": "S003",
"Full Name": "Haruna Muri",
"StudentClass": JSS 2",
"AcademicTerm": "First"
}
]
Then, in my server I have this table:
CREATE TABLE `students` (
`id` int NOT NULL auto_increment,
`registration_no` varchar(255) UNIQUE NOT NULL,
`full_name` varchar(255) UNIQUE NOT NULL,
`student_class` varchar(255) NOT NULL,
`academic_term` varchar(255) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
I am writing a cron job that will save an external api into my database using Guzzle.
I checked the site below to read some information, but I got stuck along the way.
https://appdividend.com/2018/04/17/laravel-guzzle-http-client-example/
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Student;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp;
use GuzzleHttp\Client;
class studentdataupdate extends Command {
protected $signature = 'command:studentdataupdate';
protected $description = 'Student Data Update';
public function __construct() {
parent::__construct();
}
public function handle() {
$client = new GuzzleHttp\Client();
$res = $client->request('GET','https://api.studklm.net/students/allstudents');
return $result->getBody();
$clients = json_decode($result, true);
foreach($clients as $client) {
Student::updateOrCreate([
'registration_no' => $client->Student Code,
'full_name' => $client->Full Name,
'student_class' => $client->StudentClass,
'facademic_term' => $client->AcademicTerm
]);
}
}
}
I want to achieve these results:
registration_no and full_name are unique, and should not allow duplicates
Some of the fields from the external api are not well formatted, there are spaces in between. For instance, Full Name and Student Code. How do I resolve this while trying to save into my database without error?
If Full Name or Student Code already exists, it updates. Else, it inserts the new record.
There are a couple of easy fixes for your updateOrCreate() method that may help you toward a solution.
First, you can pass strings as attributes in PHP by using curly braces. This comes in handy when there are issues like spaces, or you want to dynamically pass a variable with a string value.
// $client->{$string}
$client->{'Full Name'}
Second, updateOrCreate() accepts not one, but two arrays. The first is used to search for existing entries. The following example would update the database if the registration_no matches an existing entry, or create a new entry if not.
Student::updateOrCreate([
'registration_no' => $client->{'Student Code'},
// 'full_name' => $client->{'Full Name'}, // uncomment to use both
],
[
'full_name' => $client->{'Full Name'}, // not required if uncommented above
'student_class' => $client->StudentClass,
'facademic_term' => $client->AcademicTerm
]);
EDIT:
If you want to do registration_no OR full_name, you may have to search the values manually before updating, as updateOrCreate() uses an AND condition for searching when multiple fields are present.
Create a cron job for Laravel schedule
crontab -e
* * * * * cd /[path-to-your-laravel-project] && php artisan schedule:run >> /dev/null 2>&1
Add your console command to console/kernel.php
protected function schedule(Schedule $schedule)
{
$schedule->command('command:studentdataupdate')->everyMinute();
}
I'm trying to fill already existing models with UUID. And every time it says that UUID is not unique! What a bloody hell! )))
function unique_guid($model){
$guid = com_create_guid();
$table = $model->table;
$db_table = Db::table($table);
$req = $db_table->where("guid", strval($guid));
$instance = $req->first();
if(is_object($instance)){
$guid = unique_guid($model);
return;
}else{
try{
$model->guid = $guid;
$model->save();
sleep(2);
return $guid;
}catch(PDOException $Exception){
$guid = unique_guid($model);
}
}
}
It keeps circling in try/catch block and telling me that it is not unique,
i checked and there is no record with generated UUID.
Also - it brokes at third-fourth iteration, and if i add sleep(5) it works longer - 10 iteration and then brokes.
What in the world can it be?
Laravel 5.5, Postgres 9
Following the Laravel 6.0 official doc, I proceeded the following way:
I added the uuid-ossp extension at database creation. Then, my migrations were like:
use Illuminate\Database\Query\Expression;
...
public function up()
{
Schema::create('my_table', function (Blueprint $table) {
$table->uuid('guid')->primary()->default(new Expression('uuid_generate_v4()'));
...
});
}
I find it a lot more elegant like this.
I believe com_create_guid is not generating unique on every iteration, so please use some increment/prefix value to generated UUID, also if possible use uniqid instead of com_create_guid() uniqid generates id based on the current time in microseconds.
function unique_guid($model,$increment=0){
$guid = uniqid($increment,TRUE);
$table = $model->table;
$db_table = Db::table($table);
$req = $db_table->where("guid", strval($guid));
$instance = $req->first();
if(is_object($instance)){
$guid = unique_guid($model,++$increment);
return;
}else{
try{
$model->guid = $guid;
$model->save();
sleep(2);
return $guid;
}catch(PDOException $Exception){
$guid = unique_guid($model,++$increment);
}
}
}
I think you created function to generate UUID but there is some other better ways to generate UUID. You are using Laravel so you can search packages which are generating UUID.
There is a package I'm suggesting to use.
https://github.com/ramsey/uuid
These types of packages are useful and fully tested by community. So we can trust on them.
You can try like this.. it will check until the guid is really unique
public static function generateUniqueNumber($model = null, $column = null)
{
$num = null;
if ($model) {
$range = $model::all()->pluck('guid')->toArray();
while (in_array($num = com_create_guid(), $range)) {}
}
return $num;
}
I think it's some bug in Postgres 9.3. It inserting two rows at a time on some point of the script. I've eneded with just a migration like that
public function up()
{
DB::statement('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";');
DB::statement('ALTER TABLE feegleweb_octoshop_products ADD COLUMN guid uuid DEFAULT uuid_generate_v4() UNIQUE;');
}
It fill all my rows with unique uuid
I been trying to figure this out for some time now. Basically i got 2 models ' Recipe ', ' Ingredient ' and one Controller ' RecipeController ' .
I'm using Postman to test my API. When i go to my get route which uses RecipeController#getRecipe, the return value is as per the pic below:
Return for Get Route
If i want the return value of the get route to be in the FORMAT of the below pic, how do i achieve this? By this i mean i don't want to see for the recipes: the created_at column, updated_at column and for ingredients: the pivot information column, only want name and amount column information.
Return Value Format I Want
Recipe model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Recipe extends Model
{
protected $fillable = ['name', 'description'];
public function ingredients()
{
return $this->belongsToMany(Ingredient::class,
'ingredient_recipes')->select(array('name', 'amount'));
}
}
Ingredient Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Ingredient extends Model
{
protected $fillable = ['name', 'amount'];
}
RecipeController
<?php
namespace App\Http\Controllers;
use App\Ingredient;
use App\Recipe;
use Illuminate\Http\Request;
class RecipeController extends Controller {
public function postRecipe(Request $request)
{
$recipe = new Recipe();
$recipe->name = $request->input('name');
$recipe->description = $request->input('description');
$recipe->save();
$array_ingredients = $request->input('ingredients');
foreach ($array_ingredients as $array_ingredient) {
$ingredient = new Ingredient();
$ingredient->name = $array_ingredient['ingredient_name'];
$ingredient->amount = $array_ingredient['ingredient_amount'];
$ingredient->save();
$recipe->ingredients()->attach($ingredient->id);
}
return response()->json(['recipe' => $recipe . $ingredient], 201);
}
public function getRecipe()
{
$recipes = Recipe::all();
foreach ($recipes as $recipe) {
$recipe = $recipe->ingredients;
}
$response = [
'recipes' => $recipes
];
return response()->json($response, 200);
}
API Routes:
Route::post('/recipe', 'RecipeController#postRecipe')->name('get_recipe');
Route::get('/recipe', 'RecipeController#getRecipe')->name('post_recipe');
Thanks Guys!
I think your best solution is using Transformer. Using your current implementation what I would recommend is fetching only the needed field in your loop, i.e:
foreach ($recipes as $recipe) {
$recipe = $recipe->ingredients->only(['ingredient_name', 'ingredient_amount']);
}
While the above might work, yet there is an issue with your current implementation because there will be tons of iteration/loop polling the database, I would recommend eager loading the relation instead.
But for the sake of this question, you only need Transformer.
Install transformer using composer composer require league/fractal Then you can create a directory called Transformers under the app directory.
Then create a class called RecipesTransformer, and initialize with:
namespace App\Transformers;
use App\Recipe;
use League\Fractal\TransformerAbstract;
class RecipesTransformer extends TransformerAbstract
{
public function transform(Recipe $recipe)
{
return [
'name' => $recipe->name,
'description' => $recipe->description,
'ingredients' =>
$recipe->ingredients->get(['ingredient_name', 'ingredient_amount'])->toArray()
];
}
}
Then you can use this transformer in your controller method like this:
use App\Transformers\RecipesTransformer;
......
public function getRecipe()
{
return $this->collection(Recipe::all(), new RecipesTransformer);
//or if you need to get one
return $this->item(Recipe::first(), new RecipesTransformer);
}
You can refer to a good tutorial like this for more inspiration, or simply go to Fractal's page for details.
Update
In order to get Fractal collection working since the example I gave would work if you have Dingo API in your project, you can manually create it this way:
public function getRecipe()
{
$fractal = app()->make('League\Fractal\Manager');
$resource = new \League\Fractal\Resource\Collection(Recipe::all(), new RecipesTransformer);
return response()->json(
$fractal->createData($resource)->toArray());
}
In case you want to make an Item instead of collection, then you can have new \League\Fractal\Resource\Item instead. I would recommend you either have Dingo API installed or you can follow this simple tutorial in order to have in more handled neatly without unnecessary repeatition