how to seed in Yii? - yii

I'm wondering how one can seed in Yii a table once it is created with migration?
I've got a migration with an up-method:
public function up()
{
$this->createTable('users',array('id'=>"pk",
'login'=>'string NOT NULL'));
echo "table 'users' is created.\n";
return true;
}
I've got as well corresponding Users model and its CRUD actions. When I try to execute another migration with an up-method
public function up()
{
$user = new Users;
$user->login = "Bob";
return $user->save();
}
I get the following error:
PHP Error[2]: include(users.php): failed to open stream: No such file or directory
in file MyYiiRoot\yii\framework\YiiBase.php at line 421
I've managed to achieve the desired result by using query builder (by means of insert command), but I hope there is a nicer way out.

Use
public function safeUp()
{
$this->insert('users',array(
'login'=>'Bob'));
}
You can also do update, delete and a host of other actions. Look at http://www.yiiframework.com/doc/api/1.1/CDbMigration for more information

Related

Laravel seed table from multiple csv files

I'm very new to Laravel and Database and I'm trying to understand how to insert data into my database. Please be patient the question can sounds dummy for you.
STEP
I created a table in migrations. Example of a table:
public function up(){
Schema::create('job-urls', function (Blueprint $table) {
$table->increments('id');
$table->foreign('job_id')->references('id')->on('jobs');
$table->string('url')->index();
$table->string('hash');
$table->timestamp('created_at')->nullable();
$table->timestamp('updated_at')->nullable();
STEP
I have two csv file that correspond to the field url and hash and I want to insert them. I created a new file in migration called populate_jobs_url
class PopulateJoburls extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up(){
$fileurls = fopen('../data/urls.csv', 'r');
$filehash = fopen('../data/urls_hash.csv', 'r');
while (($row = fgetcsv($fileurls, 0, ',')) !=FALSE){
DB::table('joburls')->insert(
array(
'url' => $row,
)
);
}
while (($row = fgetcsv($filehash, 0, ',')) !=FALSE){
DB::table('joburls')->insert(
array(
'hash' => $row,
)
);
}
}
Can you help me to understand how I check if the table is correctly filled? Is this approach correct? How could I insert data otherwise in my Database? Unfortunately all examples on the web deal with inserting manually data with a form.
Thanks
Seeding the table inside of a migration file is not the best practise. You can take advantage of Seeders, which is right way to fill your table with test or actual data.
First, create a seeder file with php artisan make:seeder PopulateJobUrls command. Then you can arrange your seeder like this:
<?php
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class PopulateJobUrls extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
$fileurls = fopen('../data/urls.csv', 'r');
$filehash = fopen('../data/urls_hash.csv', 'r');
// Rest of your seeding logic...
}
}
You should reference your seeder from database/seeds/DatabaseSeeder.php in the run method:
$this->call(PopulateJobUrls::class);
Run php artisan db:seed or if you want to be more specific, php artisan db:seed --class=PopulateJobUrls and you are good to go with your correctly filled data!

symfony 4 Upload

How to upload a file in symfony 4.I have done with the symfony document. I don't know where I have missed something. Its throws error while uploading file give me some clues
REFERED LINK:
https://symfony.com/doc/current/controller/upload_file.html
ERROR:
The file "" does not exist
Entity
public function getBrochure()
{
return $this->brochure;
}
public function setBrochure($brochure)
{
$this->brochure = $brochure;
return $this;
}
File upload Listener
class FileUploader
{
private $targetDirectory;
public function __construct($targetDirectory)
{
$this->targetDirectory = $targetDirectory;
}
public function upload(UploadedFile $file)
{
$fileName = md5(uniqid()).'.'.$file->guessExtension();
$file->move($this->getTargetDirectory(), $fileName);
return $fileName;
}
public function getTargetDirectory()
{
return $this->targetDirectory;
}
}
This Symfony tutorial works fine for me so I'll try to explain how and perhaps it will help you or people still looking for an answer, this post getting a bit old.
So first you have to create the FileUploader service in App\Service for better reusability (chapter: Creating an Uploader Service). You can basically copy/paste what they've done here, it works like a charm. Then you need to open your services.yaml in Config folder and explicit your brochure directory:
parameters:
brochures_directory: '%kernel.project_dir%/public/uploads/brochures'
# ...
services:
# ...
App\Service\FileUploader:
arguments:
$targetDirectory: '%brochures_directory%'
Now everything is normally ready to use your FileUploader service.
So if you're in your controller (for example), I guess you want to use it in a form. Thus, you just have to do this (don't forget to use your Service in your Controller):
public function myController(FileUploader $fileUploader)
{
// Create your form and handle it
if ($form isValid() && &form isSubmitted()) {
$file = $myEntity->getBrochure();
$fileName = $this->fileUploader->upload($file);
$myEntity->setBrochure($fileName);
// Form validation and redirection
}
// Render your template
}
One important point I forgot to say. In your FormType, you need to say that the Brochure will be a FileType:
$builder->add('brochure', FileType::class)
But in your entity you have to specify your brochure is stored as a "string":
/**
* #MongoDB\Field(type="string")
*/
protected $brochure;
The reason is your file is getting uploaded and saved in your public/uploads/brochure. But your database is only remembering a string path to reach it.
I hope this will help!

Create tables and fill them with my own data after migration - Laravel

I have a few tables in a database that need specific data. I know I can always save the SQL command and execute them but I wonder if Laravel has some sort of specific command.
You can use seeders for test data, like #Alexey says. If you need the data to persist in all environments (e.g. local and production), you can insert the data after creating the table, with the Query Builder.
e.g.
<?php
class CreatePostsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->text('body');
$table->timestamps();
});
DB::table('posts')->insert([
'title' => 'Hello, world!',
'body' => 'This post will be created after migrating.',
]);
}
Laravel uses seeder classes to fill tables with data after migrations:
You need to create and register seeders and then run this command to run migration and seed the data:
php artisan migrate --seed

How to save content from yii widget to Database?

here is the ListBuilder Widget code:
$this->widget('ext.widgets.multiselects.XMultiSelects',array(
'leftTitle'=>'Australia',
'leftName'=>'Person[australia][]',
'leftList'=>Person::model()->findUsersByCountry(14),
'rightTitle'=>'New Zealand',
'rightName'=>'Person[newzealand][]',
'rightList'=>Person::model()->findUsersByCountry(158),
'size'=>20,
'width'=>'200px',
));
List Builder view this
I wanna save that entire list i select to right list on to my DB.
how to do this?
The source code is available so you just have to look in the controller:
public function actionMovePersons()
{
if(isset($_POST['Person']['australia']))
{
foreach ($_POST['Person']['australia'] as $id)
Person::model()->updateUserCountry($id, 14);
}
if(isset($_POST['Person']['newzealand']))
{
foreach ($_POST['Person']['newzealand'] as $id)
Person::model()->updateUserCountry($id, 158);
}
Yii::app()->user->setFlash('saved',Yii::t('ui','Data successfully saved!'));
$this->redirect(array('site/extension','view'=>'listbuilder'));
}
And in the model:
public function updateUserCountry($id, $country_id)
{
$model=$this->findByPk($id);
$model->country_id=$country_id;
$model->update('country_id');
}
The above updates the Person in the database and sets the new country. If I understand your question correct you want to create new entries (maybe in a different table) instead of changing existing ones. To do this you can easily modify the updateUserCountry() function to create a new Person instead of updating it.

Adding 'GO' statements to Entity Framework migrations

So I have an application with a ton of migrations made by Entity framework.
We want to get a script for all the migrations at once and using the -Script tag does work fine.
However...it does not add GO statements in the SQL giving us problems like Alter view should be the first statement in a batch file...
I have been searching around and manually adding Sql("GO"); help with this problem but only for the entire script. When I use the package console manager again it returns an exception.
System.Data.SqlClient.SqlException (0x80131904): Could not find stored procedure 'GO'.
Is there a way to add these GO tags only when using the -Script tag?
If not, what is a good approach for this?
Note: we have also tried having multiple files but since we have so many migrations, this is near impossible to maintain every time.
If you are trying to alter your view using Sql("Alter View dbo.Foos As etc"), then you can avoid the should be the first statement in a batch file error without adding GO statements by putting the sql inside an EXEC command:
Sql("EXEC('Alter View dbo.Foos As etc')")
In order to change the SQL Generated by entity framework migrations you can create a new SqlServerMigrationSqlGenerator
We have done this to add a GO statement before and after the migration history:
public class MigrationScriptBuilder: SqlServerMigrationSqlGenerator
{
protected override void Generate(System.Data.Entity.Migrations.Model.InsertHistoryOperation insertHistoryOperation)
{
Statement("GO");
base.Generate(insertHistoryOperation);
Statement("GO");
}
}
then add in the Configuration constructor (in the Migrations folder of the project where you DbContext is) so that it uses this new sql generator:
[...]
internal sealed class Configuration : DbMigrationsConfiguration<PMA.Dal.PmaContext>
{
public Configuration()
{
SetSqlGenerator("System.Data.SqlClient", new MigrationScriptBuilder());
AutomaticMigrationsEnabled = false;
}
[...]
So now when you generate a script using the -Script tag, you can see that the insert into [__MigrationHistory] is surrounded by GO
Alternatively in your implementation of SqlServerMigrationSqlGenerator you can override any part of the script generation, the InsertHistoryOperation was suitable for us.
Turn out the concept exist deep in the SqlServerMigrationSqlGenerator as an optional argument for Statement(sql, batchTerminator). Here is something based on Skyp idea. It works both in -script mode or not. The GOs are for different operations than for Skyp only because our needs are a little different. You then need to register this class in the Configuration as per Skyp instructions.
public class MigrationScriptBuilder : SqlServerMigrationSqlGenerator
{
private string Marker = Guid.NewGuid().ToString(); //To cheat on the check null or empty of the base generator
protected override void Generate(AlterProcedureOperation alterProcedureOperation)
{
SqlGo();
base.Generate(alterProcedureOperation);
SqlGo();
}
protected override void Generate(CreateProcedureOperation createProcedureOperation)
{
SqlGo();
base.Generate(createProcedureOperation);
SqlGo();
}
protected override void Generate(SqlOperation sqlOperation)
{
SqlGo();
base.Generate(sqlOperation);
}
private void SqlGo()
{
Statement(Marker, batchTerminator: "GO");
}
public override IEnumerable<MigrationStatement> Generate(IEnumerable<MigrationOperation> migrationOperations, string providerManifestToken)
{
var result = new List<MigrationStatement>();
var statements = base.Generate(migrationOperations, providerManifestToken);
bool pendingBatchTerminator = false;
foreach (var item in statements)
{
if(item.Sql == Marker && item.BatchTerminator == "GO")
{
pendingBatchTerminator = true;
}
else
{
if(pendingBatchTerminator)
{
item.BatchTerminator = "GO";
pendingBatchTerminator = false;
}
result.Add(item);
}
}
return result;
}
}
The easiest way is to add /**/ before the GO statement.
Just replace the current statement with a .Replace("GO", "");