This forum has moved to a new location and is in read-only mode. Please visit talk.octobercms.com to access the new location.
Hello, I've written a new tutorial on how to use the new import and export feature of October - it's on OctoHelp
http://octo-help.com/how-to-use-the-new-import-and-export-feature-in-october/
Thanks for cool articles. Can you say some words about import "has many" relations to database. As i understand, all logics in importModel class, but what about "Has many"? How talk to controller import fields correctly? Thanks, Filip for your work.
yeah, that's true but i wanted to name them the same - controller + model :) it was not by mistake, i just wanted to name them that way.
Filip Pacurar said:
yeah, that's true but i wanted to name them the same - controller + model :) it was not by mistake, i just wanted to name them that way.
This is a bad practice for a couple of reasons... First, if you want to use your model in your controller, you now have to use aliases which gets annoying. But the bigger problem is that a model in active record (like eloquent) refers to a single row in the database. alxy is correct, models should be singular, controllers should be plural.
Last updated
Lol:
$car = Cars::find(1);
var_dump($cars instanceof Cars); // true
I just wanted to name them that way.
Ignoring conventions on purpose and basically on a whim is not only bad practice - it's evil. You break the implicit semantic contract between people using your code in community that generally agrees with convention. If I have classes 'Car' and 'Cars' then I know without even looking at namespaces what type of classes I have - an entity and a controller. You present no reason to break convention and moreover you publish tutorial material promoting your mistake without mentioning in said article that you are breaking a convention and that is on a whole new level of evil.
Last updated
Just updated my tutorial guys, don't panic anymore, lol! http://octo-help.com/how-to-use-the-new-import-and-export-feature-in-october/
Import / Export with relationship!
In this tutorial I will try to explain how to export / import data with related models. Before continue, please read the excellent tutorial "How to use the new Import and Export feature in October".
Plugin settings
In a basic example, we have the models Book
, Author
, Contact
and Category
Table structure
books
id
title
description
author_id
book_categories
book_id
category_id
categories
id
name
authors
name
email
contacts
name
author_id
Models relationships
Book
public $belongsToMany = [
'categories' => [
'Acme\Books\Models\Category',
'table' => 'book_categories'
]
];
public $belongsTo = [
'author' => ['Acme\Books\Models\Author']
];
Author
public $hasMany = [
'contacts' => ['Acme\Books\Models\Contact'],
'books' => ['Acme\Books\Models\Book']
];
Contact
public $belongsTo = [
'author' => ['Acme\Books\Models\Author']
];
Controller yaml file for Import/Export
File controllers/books/config_import_export.yaml
# ===================================
# Import/Export Behavior Config
# ===================================
import:
title: Import books
modelClass: Acme\Books\Models\BookImport
list: $/acme/books/models/book/import_export_columns.yaml
export:
title: Export books
modelClass: Acme\Books\Models\BookExport
list: $/acme/books/models/book/import_export_columns.yaml
I prefer to use a separate yaml file for import/export than controller column lists
File acme/books/models/book/import_export_columns.yaml
columns:
id:
label: ID
title:
label: Book title
description:
label: Book description
author:
label: Author
categories:
label: Categories that belongs
Import / Export models
Export model
<?php namespace Acme\Books\Models;
use Backend\Models\ExportModel;
/**
* BookExport Model
*/
class BookExport extends ExportModel
{
public function exportData($columns, $sessionKey = null)
{
$books = Book::with([
'author.contacts' => function($query){ $query->addSelect(['name', 'author_id']); },
'author' => function($query){ $query->addSelect(['id', 'name', 'email']); },
'categories' => function($query){ $query->addSelect(['name']); }
])->get();
$books->each(function($book) use ($columns) {
/** @var Book $book */
$book->addVisible($columns);
});
$collection = collect($books->toArray());
$data = $collection->map(function ($item) {
if(is_array($item)){
foreach($item as $key => $value) {
if(is_array($value)) {
$item[$key] = json_encode($value);
}
}
}
return $item;
});
return $data->toArray();
}
}
Import model
<?php namespace Acme\Books\Models;
use Backend\Models\ImportModel;
/**
* BookImport Model
*/
class BookImport extends ImportModel
{
/**
* @var array The rules to be applied to the data.
*/
public $rules = ['name' => 'required', 'author' => 'required', 'categories' => 'required'];
public function importData($results, $sessionKey = null)
{
foreach ($results as $row => $data) {
try {
// First create the Author if not exists
$author_data = (!is_array($data['author'])) ? json_decode($data['author']) : $data['author'];
$modelAuthor = null;
if(is_array($author_data) && count($author_data)) {
$modelAuthor = Author::whereEmail($author_data['email']);
if(!$modelAuthor) {
$modelAuthor = Author::create(['name' => $author_data['name'], 'email' => author_data['email']]);
if(array_key_exists('contacts', $author_data)) {
foreach($author_data['contacts'] as $author_contact){
Contact::create(['name' => $author_contact['name'] , 'author_id' => $modelAuthor->id ]);
}
}
}
}
// Create/Update the Book model
$book_data = [
'title' => $data['title'],
'description' => $data['description']
];
if($modelAuthor) {
$book_data['author_id'] = $modelAuthor->id;
}
if(array_key_exists('id', $data)){
$book = Book::find($data['id']);
$book->update($book_data);
} else {
$book = Book::create($book_data);
}
// Add categories
$categories_data = (!is_array($data['categories'])) ? json_decode($data['categories']) : $data['categories'];
if (is_array($categories_data) && count($categories_data)) {
$cd = collect($categories_data);
$cd->forget('pivot');
$cd->each(
function ($category) use ($book) {
$name = $category->name;
if (!$book->categories()->whereName($name)->count()) {
$modelCategory = Category::whereName($name)->first();
if (!$modelCategory) {
$modelCategory = Category::create($category->toArray());
}
$book->categories()->attach($modelCategory->id);
}
}
);
}
if (array_key_exists('id', $data)) {
$this->logUpdated();
} else {
$this->logCreated();
}
} catch (\Exception $ex) {
$this->logError($row, $ex->getMessage());
}
}
}
}
Sorry my english. I hope to help someone.
Thanks
Last updated
thanks planetadeleste, very useful code :)
i was wondering 2 things :
- how the book import files is looking ? do you have an example ?
- was is the purpose of the function collect() used for the categories ?
thanks
@chris10207; The exported csv file look something like this:
Id,Title,Description,Author,Category
1,"Code Smart","Code Smart contains everything you need to know to get building your own Laravel applications. It's written for human beings using simple language, as if we were chatting together in a pub.","{""name"":""Dayle Rees"",""email"":""info@daylerees.com"",""contacts"":"[{""name"":""Contact Name 1""}, {""name"":""Contact Name 2""}]"}","[{""name"":""Programming""},{""name"":""PHP""},{""name"":""Laravel 5""}]"
The use of collect
is to have more control over category data, using Collections
. But you can use native php functions.
Hi thanks for this, and how about the original import file ? im struggling with the is_array() and json things in the import file.
@chris10207 I use json_encode
and json_decode
because I don't found another way to store relation data, like author
and/or category
. If your export/import data doesn't have or need relationship, you don't need the use json encoder/decoder.
The use of is_array()
is only to prevent php Exceptions in json_decode()
. But I think this data always be a string.
Sorry if my English is not quite right.
Nope, my crystal ball doesn't show your code. Make a new topic in which you outline your code and problem.
Prefably in a http://stackoverflow.com/help/mcve way...
Last updated
I think the import post tool included in Blog Plugin es great, but I can´t find the way to import the featured images from my wordpress blog or joomla site. Every document I readed talks just about import text, but nothing about import post images, specially the featured image. Anyone knows how to do this? Do I need to develop a plugin for this purpose?
@PolloZen, in your case, I think, the best way is upload the images in some temporary folder, them in your import script method, find for the reference to the current image with the uploaded file.
Read the Attachments documentation.
The Import/Export utility is for CSV files, is only in your brain how you want to process the imported data.