Foreign keys and uploading a photo in yii 1.1 - mysql

i did these two tasks separately but now i am not being able to use both of these tasks at a single place.
Problem statement:
I have a table name Business_items having foreign keys of table business and items. In model class here is the relation function.
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'business' => array(self::BELONGS_TO, 'Business', 'business_id'),
'items' => array(self::BELONGS_TO, 'Items', 'items_id'),
'itemReviews' => array(self::HAS_MANY, 'ItemReview', 'business_items_id'),
);
}
ok, in create business page, i have two fields, business name, items name and a third thing which is upload image. Both of the fields are searchable drop downs. I am taking business name and items name with the help of foreign keys. so i can see the values inside my business_items which were used to be keys. i did this by changing this code.
public function actionCreate()
{
$model=new PackageItems;
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
if(isset($_POST['PackageItems']))
{
$temp=$model->items_id=$_POST['PackageItems']['items_id']; //items_id is a multiple list field
foreach($temp as $t)
{
$model->unsetAttributes();
$model->setIsNewRecord(true);
$model->package_id=$_POST['PackageItems']['package_id']; //package_id is a repeated field
$model->items_id=$t;
$model->insert();
}
if($model->save())
$this->redirect(array('admin','id'=>$model->id));
}
$this->render('create',array(
'model'=>$model,
));
}
so what i wanted i actually accomplished which was
id----items----package
1------cake-----buy one get one free
2----- pastry-----buy one get one free
second part:
I know how to upload image in yii, i followed this link and it worked http://www.yiiframework.com/wiki/349/how-to-upload-image-photo-and-path-entry-in-database-with-update-functionality/
separately now the problem is i want something like that
id----items----package-----------------------image
1------cake-----buy one get one free------1.jpg
2----- pastry-----buy one get one free------1.jpg
but the problem is
public function actionCreate()
{
$model=new Banner; // this is my model related to table
if(isset($_POST['Banner']))
{
$rnd = rand(0,9999); // generate random number between 0-9999
$model->attributes=$_POST['Banner'];
$uploadedFile=CUploadedFile::getInstance($model,'image');
$fileName = "{$rnd}-{$uploadedFile}"; // random number + file name
$model->image = $fileName;
if($model->save())
{
$uploadedFile->saveAs(Yii::app()->basePath.'/../banner/'.$fileName); // image will uplode to rootDirectory/banner/
$this->redirect(array('admin'));
}
}
$this->render('create',array(
'model'=>$model,
));
}
how can i use both of these codes (getting value using foreign key code and picture uploading code) i want to upload pictures as well as get the value from some other table using foreign key with my code.
I know its complicated but i need help.
Thanks and sorry in advance.

I'm not sure if I get your problem right, but as far as I understood, you want to upload a file and insert the name of this file in one of your database tables. If that's the case, a solution could be as follows:
First, add a new field to your database table in which you will store the file name, also add it to your ActiveRecord class and to your view.
Then add your code to save your related records (I think your foreach loop is for that).
Next add a the necessary code to upload the image. In the code to upload the image you can see that Yii will treat the file field like a normal text field, in which you will store the uploaded file name.
Finally you should save your model and, if it succeded, then proceed to save the file in the server.
Hope this helps.
UPDATE
I'll put some code in order to clarify my answer.
You say that the first part works for you, then I'll begin with that.
Your model PackageItems needs a new field, let it be image.
Next, I'm assuming that the user filled the form, so I'll skip the if and the render parts
$temp=$model->items_id=$_POST['PackageItems']['items_id'];
$uploadedFile=CUploadedFile::getInstance($model,'image');//get uploaded image info
$rnd = rand(0,9999);
$fileName = "{$rnd}-{$uploadedFile}"; // random number + file name
$model->image = $fileName;//store the new file name in the model
foreach($temp as $t){
$model->unsetAttributes();
$model->setIsNewRecord(true);
$model->package_id=$_POST['PackageItems']['package_id'];
$model->items_id=$t;
$model->insert();
}
if($model->save()){
$uploadedFile->saveAs(Yii::app()->basePath.'/../yourPath/'.$fileName);//if the record was saved in the database, then proceed to save the image in the server
$this->redirect(array('admin','id'=>$model->id));
}
If you want to upload multiple files check this link Yii 1.1: Uploading multiple images with CMultiFileUpload

Related

inserting data to multiple tables from a single imported CSV in laravel

I'm trying to import CSV file in laravel that contains data to be stored in multiple tables in mysql database. Actually I've Contacts with multiple emails, addresses, phones etc so i want them to store in their respective table along with the contactId of the contact newly created from the CSV.
For now insertion in single table is working but when i introduce columns like email, address etc that are to be inserted in other tables, it gives me column not found in Contact table as email address etc column is not there.
Controller Method for Insertion
public function processImport(Request $request){
$data = CsvData::find($request->csv_data_file_id);
$csv_data = json_decode($data->csv_data, true);
foreach ($csv_data as $row) {
$contact = new Contact(); //Insertion in Contact table
foreach (config('app.contact_fields') as $index => $field) {
if ($data->csv_header) {
$contact->$field = $row[$request->fields[$field]];
} else {
$contact->$field = $row[$request->fields[$index]];
}
}
$contact->save(); //Insertion in Contact table
$id = $contact->id;
}
return 'Successfully imported!';
}
Now i want to know is there any way we can separate columns to be inserted into separate tables from the single CSV imported ?
Any help would be highly appreciated.
Thanks
You have to execute multiple queries inside the foreach() loop, because you have multiple tables. Without knowing the both structure of the CSV file and the tables in question it is difficult to specify any further.

Expanding this method to write to the database

Hi I followed a tutorial to implement a friend system. It all works find, but I need to post other columns to the row that just the id's. How would I expand that.
This is the method that is accessed when the add friend button is clicked
public function getAdd($id){
$user = User::where('id', $id)->first();
//After passing all checks. Add other account
Auth::user()->addFriend($user);
echo "Sent";
}
AddTenancy Method
public function addFriend(User $user){
$this->friendsOf()->attach($user->id);
}
I assume the relationship is many-to-many between users. And you need to add additional data to the pivot.
Here's how you'd do that:
public function addFriend(User $user){
$this->friendsOf()->attach($user->id, ['another_col' => 'some data']);
}
Replace 'another_col' and some data with your column and your data. You can also add more than 1 column into the array.

yii2 getting data from two models and presenting it in view

I have two models users and pictures
To draw all pictures in view I have to get string from pictures, one of data is userID, then get string from users according to that userID, so I get userFolder
Then I can draw picture using combined data.
And this must be done for all pictures in DB.
I can start from controller
$picturesModel= Pictures::find()->all();
But then I have to do what? run a loop while which get users data, and then get complete data for drawing a picture and store it in some new array which after loop finish I should pass to view? Is this the best way ? or there is anything simple ?
Assuming that your Pictures has a relation one to one with Users
the you can add to you Pictures model a function
class Pictures extends ActiveRecord
{
// ...
public function getUser()
{
return $this->hasOne(Users::className(), ['id' => 'user_id']);
}
}
then if you controller or in your view you need accessing to the user related to the picture you can
$pictureModel = Pictures::find()->where(['id'=>123])->one();
You can access to the user related
$userModel= $pictureModel->User;
or for a collection of pictures
$picturesModels= Pictures::find()->all();
$userModel = $picturesModels[0]->user
or for the loop
$picturesModels= Pictures::find()->all();
foreach( $picturesModels as $key => $value ) {
echo $value->user->your_att;
}
you can take a look at http://www.yiiframework.com/doc-2.0/guide-db-active-record.html and http://www.yiiframework.com/doc-2.0/guide-db-active-record.html#relational-data

Several identical relations to one model in Yii2

I have a model File to store uploaded files and information about these files. Also there is a model with Company relations logo hasOne(File::className()) and photos hasMany(File::className()). Relations are written and works fine. Now I need to make an edit form for model Company in which I could edit files associated in logo and photos. Please tell me how I can do it.
Your relations can reflect the different use-cases, so in your Company model you can have
public function getLogo(){
//You'll need to add in the other attributes that define how Yii is to retrieve the logo from your images
return $this->hasOne(File::className(), ['companyId' => 'id', 'isLogo' => true]);
}
public function getPhotos(){
//You'll need to add in the other attributes that define how Yii is to retrieve the photos from your images
return $this->hasMany(File::className(), ['companyId' => 'id', 'isLogo' => false]);
}
You can then just use them like normal attributes;
$company = new Company;
$logo = $company->logo;
$photos = $company->photos;
You will then need to set up your controller to handle changes in these values to deal with uploads or new images, but that will depend on how you are handling the uploads.

Yii model: Dynamic table relations

Table.linkedIndex is related to LinkedIndex.ID. The value of the field LinkedIndex.TableName is either Linked1 or Linked2 and defines which of these tables is related to a row in Table.
Now i want to make a dynamical link with Yii models so that i can easily get from a Table row to the corresponding Linked1 or Linked2 row:
Table.linkedID = [LinkedIndex.TableName].ID
Example
Table values:
LinkedIndex values:
Now I should get the row from Linked2 where ID=2:
$model = Table::model()->findByPk(0);
$row = $model->linked;
Model
In the model Table, I tried to make the relation to the table with the name of the value of linkedIndex.TableName:
public function relations()
{
return array(
'linkedIndex' => array(self::HAS_ONE, 'LinkedIndex', array('ID' => 'linkedIndex')),
'linked' => array(
self::HAS_ONE,
'linkedIndex.TableName',
array('ID' => 'linkedID'),
)
)
}
But then I get the error:
include(linkedIndex.TableName.php) [function.include]: failed to open stream: No such file or directory
Is there any way to make a dynamic relation Table.linkedID -> [LinkedIndex.TableName].ID with Yii Models?
Per the Yii docs here:
http://www.yiiframework.com/doc/api/1.1/CActiveRecord#relations-detail
I'd suggest using self::HAS_ONE instead (unless there can be multiple rows in LinkedIndex with the same ID - although from the looks of above, I doubt that's the case).
You can link tables together that have different keys by following the schema:
foreign_key => primary_key
In case you need to specify custom PK->FK association you can define it as array('fk'=>'pk'). For composite keys it will be array('fk_c1'=>'pk_с1','fk_c2'=>'pk_c2').
so in your case:
public function relations(){
return array(
'linkedIndex' => array(self::HAS_ONE, 'LinkedIndex', array('ID' => 'linkedIndex')),
);
}
where LinkedIndex is the class name for the LinkedIndex model (relative to your Table model - i.e. same folder. You could change that, of course) and array('ID' => 'linkedIndex') specifies the relationship as LinkedIndex.ID = Table.linkedIndex.
Edit
Looking at your updated example, I think you're misunderstanding how the relations function works. You're getting the error
include(linkedIndex.TableName.php) [function.include]: failed to open stream: No such file or directory
because you're trying to create another relation here:
'linked' => array(
self::BELONGS_TO,
'linkedIndex.TableName',
array('ID' => 'linkedID'),
)
This part: linkedIndex.TableName refers to a new model class linkedIndex.TableName, so Yii attempts to load that class' file linkedIndex.TableName.php and throws an error since it doesn't exist.
I think what you're looking for is to be able to access the value TableName within the table LinkedIndex, correct? If so, that's accessible from within the Table model via:
$this->linkedIndex->TableName
This is made possible by the relation we set up above. $this refers to the Table model, linkedIndex refers to the LinkedIndex relation we made above, and TableName is an attribute of that LinkedIndex model.
Edit 2
Per your comments, it looks like you're trying to make a more complex relationship. I'll be honest that this isn't really the way you should be using linking tables (ideally you should have a linking table between two tables, not a linking table that says which 3rd table to link to) but I'll try and answer your question as best as possible within Yii.
Ideally, this relationship should be made from within the LinkedIndex model, since that's where the relationship lies.
Since you're using the table name as the linking factor, you'll need to create a way to dynamically pass in the table you want to use after the record is found.
You can use the LinkedIndex model's afterFind function to create the secondary link after the model is created within Yii, and instantiate the new linked model there.
Something like this for your LinkedIndex model:
class LinkedIndex extends CActiveRecord{
public $linked;
public static function model($className = __CLASS__){
return parent::model($className);
}
public function tableName(){
return 'LinkedIndex';
}
public function afterFind(){
$this->linked = new Linked($this->TableName);
parent::afterFind();
}
//...etc.
}
The afterFind instantiates a new Linked model, and passes in the table name to use. That allows us to do something like this from within the Linked model:
class Linked extends CActiveRecord{
private $table_name;
public function __construct($table_name){
$this->table_name = $table_name;
}
public static function model($className = __CLASS__){
return parent::model($className);
}
public function tableName(){
return $this->table_name;
}
//...etc.
}
which is how we dynamically create a class with interchangeable table names. Of course, this fails of the classes need to have separate operations done per-method, but you could check what the table_name is and act accordingly (that's pretty janky, but would work).
All of this would result in being to access a property of the linked table via (from within the Table model):
$this->linkedIndex->linked->foo;
Because the value of LinkedIndex.TableName and Table.linkedID is needed to get the values, I moved the afterFind, suggested by M Sost, directly into the Table-Class and changed its content accordingly. No more need for a virtual model.
class Table extends CActiveRecord {
public $linked; // Needs to be public, to be accessible
// ...etc.
public function afterFind() {
$model = new $this->linkedIndex->TableName;
$this->linked = $model::model()->findByPk( $this->linkedID );
parent::afterFind();
}
// ...
}
Now I get the row from Linked2 where ID=2:
$model = Table::model()->findByPk(0);
$row = $model->linked;