Magento 2.3. - custom import module with Magmi Integration - magento

I'm trying to write a magento modulo for importing products from a csv file. I would like to use Magmi to achieve the import. I tried the following code but it doesn't work.
namespace My\Module\Controller\Adminhtml\Home;
require_once(dirname(__FILE__) . "/../../../../../../../lib/magmi/inc/magmi_defs.php");
require_once(dirname(__FILE__) . "/../../../../../../../lib/magmi/integration/inc/magmi_datapump.php");
class Import extends \Magento\Backend\App\Action{
public function execute()
{
// getting data from a casv file
for ($items as $item){
$dp = Magmi_DataPumpFactory::getDataPumpInstance("productimport");
$dp->beginImportSession("default", "xcreate");
$item = "product field array";
$run = $dp->ingest($item);
$dp->endImportSession();
}
}
}
I receive errors on the Magmi classes "class not found". I tried also different code but the only way a think it can works is using class file named, e.g. Datapump.php with e defined class named Datapump. But I cannot rewrite all files of magmi to make it works, so maybe I'm doing something wrong.

Though not an ideal solution. But you can try this.
1) Make below changes in file magmi/integration/inc/magmi_datapump.php
Change the class name from 'Magmi_DataPumpFactory' to 'Magmi_DataPump'
This is needed because Magento 2 interprets Factory keyword in a different way.
2) Now create an autoloader file
app/code/Vendor/Module/magmi-autoloader.php
<?php
$mapping = array(
'Magmi_Defs' => BP . '/magmi/inc/magmi_defs.php"',
'Magmi_DataPump' => BP . '/magmi/integration/inc/magmi_datapump.php'
);
spl_autoload_register(function ($class) use ($mapping) {
if (isset($mapping[$class])) {
require $mapping[$class];
}
}, true);
3) Now change relative paths in below file to absolute path. Since while running magmi classes through Magento, it will be not able to read paths relative to magmi directory.
magmi/inc/magmi_defs.php
<?php
// change below define variables to their absolute paths according to your project's root directory
define("MAGMI_BASEDIR", dirname(dirname(__FILE__)));
define("MAGMI_INCDIR", MAGMI_BASEDIR . '/inc');
define("MAGMI_INTEGRATION_INCDIR", MAGMI_BASEDIR . '/integration/inc');
define("MAGMI_PLUGIN_DIR", MAGMI_BASEDIR.'/plugins');
define("MAGMI_ENGINE_DIR", MAGMI_BASEDIR . '/engines');
.
.
//other code
.
.
4) Now change your controller file as below
<?php
namespace Vendor\Module\Controller\Adminhtml\Home;
require BP.'/app/code/Vendor/Module/magmi-autoloader.php';
class Import extends \Magento\Backend\App\Action
{
public function execute()
{
// getting data from a csv file
$dp = \Magmi_DataPump::getDataPumpInstance("productimport");
// move this outside the loop to prevent mysql max_connection error
$dp->beginImportSession("default", "xcreate");
for ($items as $item){
$item = "product field array";
$run = $dp->ingest($item);
}
$dp->endImportSession();
}
}

Related

How to get $config['imgURL_Path'] value from CodeIgniter's file config.php NOT from CI controller?

I want to get some constants, defined in CodeIgnitor in /application/config/config.php, but when i am outside CI controller. For example, i have a file that generates image thumbs or something else, that is outside CodeIgniter mvc framework. Cause the file /application/config/config.php has a string:
defined('BASEPATH') OR exit('No direct script access allowed');
i can't just do something like :
include '/application/config/config.php';
$imgPath = $config['imgURL_Path'];
I tried to add this strings, but no result:
if (defined('STDIN'))
{
chdir(dirname(__FILE__));
}
if (($_temp = realpath($system_path)) !== FALSE)
{
$system_path = $_temp.'/';
}
else
{
// Ensure there's a trailing slash
$system_path = rtrim($system_path, '/').'/';
}
// Is the system path correct?
if ( ! is_dir($system_path))
{
header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
echo 'Your system folder path does not appear to be set correctly. Please open the following file and correct this: '.pathinfo(__FILE__, PATHINFO_BASENAME);
exit(3); // EXIT_CONFIG
}
define('BASEPATH', str_replace('\\', '/', $system_path));
include '/application/config/config.php';
$imgPath = $config['imgURL_Path'];
i also tried to make a file ci.php with this content:
<?php
// file: ci.php
ob_start();
require_once '../index.php';
ob_get_clean();
return $CI;
?>
and use it like:
$CI = require_once 'ci.php';
$imgPath = $CI->config->item('imgURL_Path');
but also no luck. What can be the solution?
If you want an URL_path or a variable that can be accessed anywhere, you can use helper.
1 Create a file in folder helpers, let's say you named it myvariable_helper.php //make sure you add '_helper' before the .php.
2 Open autoload in config folder, then search for $autoload['helper']
, insert your newly created helper there like this: $autoload['helper'] = array(url, myvariable)
3 Save the autoload, then open myvariable_helper.php, and add a function. Let's say you add an URL to a function like this:
<?php
function img_path()
{
$imgURL_Path = 'www.your_domain.com/image/upload';
return $imgURL_Path;
}
4 Call the function anywhere (even outside your MVC folder), using the function name, for example:
public function index()
{
$data['url'] = img_path(); //assign the variable using return value (which is 'www.your_domain.com/image/upload')
$this->load->view('Your_View', $data); //just for example
}
Note:
This helper can't be accessed from browser (like your model folder), so it's safe

Magento importing images

I am getting stuck with images not displaying with their products. When I create a product and insert an image with that product manually through (manage products) the image shows which is great.
However we have over 1000 product images which need to be uploaded, (all the product information is already up I just need to add the images)
I have exported the products CSV file and the working image address is /n/g/image1.jpg
I have then copied that but change the image to image2.jpg, image3.jpg etc. I then uploaded the new images into that folder directory on our server thinking that's enough.
I then upload the CSV file blow the cache and reindex the data however no new images show and worse the working image doesn't display.
I have filled in image, small_image and thumbnail details in the CSV. All images are correctly sized etc.
Further more can allow tell me where I can just have 1 image folder in the directory where all my images are stored?
Thanks
I'm using Magento version 1.7.0.2
First of all your image should store in media>import directory
then in your csv file just write in image column /imagename.jpg
it will find same imagename in import directory, if image exist then it will upload the image
EDIT
if you don't have import directory then simply create it
I'm sorry to say, but there is more going on behind the scenes with magento images that it simply putting a filename in the database and linking to your image. The cache generation alone is pretty complex. I believe you are going to have a hard time doing it the way you are attempting.
That being said, I do have a suggestion. Since your images are already on the server, I suggest you write a simple php script to tell magento to attach them to the product image. This could be automated, but i'll give you a small example below...
To attach an image, you would simply navigate to the url like this
http://yoursite.com/imageattacher.php?sku=YOURSKU&image=yourimagefilename.jpg
The script would be like this... create a file in your magento ROOT and call it imageattacher.php. Upload your images to the magento media import directory. I have not tested this but it should work.
<?php
// Initialize magento for use outside of core
umask(0);
require_once 'app/Mage.php';
Mage::app('admin');
// Get the variables from the URL
$sku = $_GET["sku"];
$imageName = $_GET["image"];
// get the image from the import dir
$import = Mage::getBaseDir('media') . DS . 'import/' . $imageName;
// Load the product by sku
$product = Mage::getModel('catalog/product')->loadByAttribute('sku',$sku);
// if the product exists, attempt to add the image to it for all three items
if ($product->getId() > 0)
{
// Add the images and set them for their respective usage (the radio button in admin)
$product->addImageToMediaGallery($import,array('image', 'small_image', 'thumbnail'),false,false);
// Make the changes stick
$product->save();
}
?>
See this http://www.danneh.org/2012/05/creating-products-programmatically-magento/
The issue in the end was that there wasn't an import folder under the media directory. The images were uploaded to this folder. The image column in the CSV was changed to /image1.jpg which allowed them to show on the website.
I had to import a bunch of Magento product images recently which were all named by SKU (eg 123456.jpg). This is the script I used to import them, parts of which are based on CarComp's answer. It will only work for numeric SKUs (eg 123456) but could be fairly easily modified to cater for alphanumeric ones.
<?php
require_once(__DIR__ . "/app/Mage.php");
Mage::app('admin');
class Sku_ImageLoader {
private $_uploadDir;
private $_imagePaths;
public function setUploadDirectory($dir = null) {
if (empty($dir)) {
if (isset($this->_uploadDir)) return $this;
$dir = 'upload';
}
$this->_uploadDir = Mage::getBaseDir('media') . DS . $dir;
// mkdir($this->_uploadDir . DS . "/loaded", 0770);
return $this;
}
public function load() {
$this->setUploadDirectory();
// Match product images like 123456.jpg
$pattern = '[0-9][0-9][0-9][0-9][0-9][0-9].{jpg,gif,png}';
chdir($this->_uploadDir);
$this->_imagePaths = glob($pattern, GLOB_BRACE);
return $this;
}
public function showFiles() {
$this->load();
echo "\r\n\r\nSorry, I wasn't able to upload the following image files in " . $this->_uploadDir . "\r\n\r\n<pre>\r\n";
print_r($this->_imagePaths);
return $this;
}
private function _addImage($path) {
$sku = (string)intval($path);
try {
echo "Loading SKU: {$sku} ... ";
$product = Mage::getModel('catalog/product')->loadByAttribute('sku',$sku);
// if the product exists, attempt to add the image to it for all three items
if (strpos(get_class($product), 'Catalog_Model_Product') !== false && $product->getId() > 0) {
$product->addImageToMediaGallery($path,array('image', 'small_image', 'thumbnail'),false,false);
$product->save();
echo " ok \r\n";
return true;
}
} catch (Exception $e) {
echo "Exception thrown for {$sku}: " . $e->getMessage() . "\r\n";
}
echo " (FAILED) \r\n";
return false;
}
private function _moveImage($path) {
// rename($path, 'loaded' . DS . $path);
unlink($path);
}
public function import() {
echo "<pre>\r\n";
if (!isset($this->_imagePaths)) $this->load();
foreach ($this->_imagePaths as $path) {
if ($this->_addImage($path)) {
$this->_moveImage($path);
}
}
return $this;
}
}
$u = new Sku_ImageLoader();
$u->import()->showFiles();
?>

Codeigniter: Unable to locate the specified class: Exceptions.php

Here's my controller:
$html = $this->load->view('print_po', $po, TRUE);
$this->load->library('pdf');
$pdf = $this->pdf->load();
Now I've tried and comment each line and the one that shows the error is:
$pdf = $this->pdf->load();
Here's my library class in application/libraries:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
class pdf {
function pdf()
{
$CI = & get_instance();
log_message('Debug', 'mPDF class is loaded.');
}
function load($param=NULL)
{
include_once APPPATH.'/third_party/mpdf/mpdf.php';
if ($params == NULL)
{
$param = '"en-GB-x","A4","","",10,10,10,10,6,3';
}
return new mPDF($param);
}
}
The error comes only after moving the code from one server to another(the error happens on a CentOS server which I bet is case sensitive). My question here would be: what should I modify so codeIgniter loads Exceptions.php normally?
First, remove the forward-slash at the first of /third_party phrase:
include_once APPPATH.'third_party/mpdf/mpdf.php';
CodeIgniter defines APPPATH constant with a trailing slash. Take a look at index.php:
define('APPPATH', $application_folder.'/');
Second, make sure that the file/folder names are as the same as you have wrote. It's better to keep them all lowercase. Here is a related topic.
Update:
The class name should be Capitalized. In this case change the pdf to Pdf:
class Pdf {
// ...
}
From CI Documentation:
Naming Conventions:
File names must be capitalized. For example: Myclass.php
Class declarations must be capitalized. For example: class Myclass
Class names and file names must match.

Two or more loaded controllers with the same name "admin" are not working in HMVC in CodeIgniter

The structure looks like this:
modules
admin
controllers/
admin.php
models/
admin_model.php
views/
admin/
index.php
categories/
controllers/
admin.php
categories.php
models/
categories_model.php
views/
admin/
index.php
menu.php
frontpage.php
posts/
controllers/
admin.php
posts.php
models/
posts_model.php
views/
admin/
index.php
menu.php
frontpage.php
The admin controller looks like:
class Admin extends Backend_Controller {
function __construct()
{
parent::__construct();
$this->load->model('categories_model');
}
public function index()
{
// index stuff
}
public function _menu()
{
$this->load->view('categories/admin/menu');
}
}
And when I am calling it from another module view like this:
<?php echo Modules::run('categories/admin/_menu'); ?>
it doesn't work ;(
However this works:
<?php echo Modules::run('categories/categories'); ?>
So my problem is how to load the controller with a name admin and not the name as the module's name and the method "menu"
Any idea how could I make it work in CodeIgniter?
EDIT:
I have found out that if I change my controller name from "admin" to something else e.g. "blablacontroller" it magically starts working.
I have already another module called "admin" so could this be a problem?
If I'm right, you are using Modular Extensions - HMVC. So I've based my answer on the following script : https://bitbucket.org/wiredesignz/codeigniter-modular-extensions-hmvc/src/868e97533562e910d8263af22750985d57004baa/third_party/MX/Modules.php?at=default.
This will only work if you are using PHP 5.3 or above.
Declare every Admin classes inside a namepsace (admin, categories, post) by adding namespace admin; before the class keywork.
Create a child class of *third_party/MX/Modules.php* and extend the run and load methods. If extending is not possible, you'll have to replace the methods :/
This is not the whole thing, but those simples string operations should be in the load method before the existing logic.
A module should be run with the following syntax : *Modules::run('categories\admin/_menu');*
$module = 'categories\admin';
if (strpos($module, '\\') !== false)
{
// Extract namespace
$ns = explode('\\', $module);
// Get the top level namespace to locate the controller
$top_level_ns = reset($ns); //
// Remove namespace from module
$module = array_pop($ns);
// Class location
$path = APPPATH . $top_level_ns . '/controllers/' . $module;
// It's better to extend the load_file method
include_once $path . EXT;
// Full class name with namespace, we use explode on $module in case of sub folders
$controller = '\\' . implode('\\', $ns) . '\\' . ucfirst(end(explode('/', $module))) . CI::$APP->config->item('controller_suffix');
// create and register the new controller
$alias = strtolower($controller);
self::$registry[$alias] = new $controller($params);
var_dump('Full class name: ' . $controller, 'Class path: ' . $path);
}
In PHP you can only have a single class declared with a name. Eg. you can only have a single Admin class unless the classes are in different namespaces. What might be happening is:
admin/controllers/admin.php is declared then later in your scripts execution categories/controllers/admin.php is attempted to be declared and throws an error as admin/controllers/admin.php already exists and which Admin class should it use if some code somewhere says new Admin().
If both classes are needed then one will need to renamed, or the code to be restructured so that only one of them is declared in a single execution cycle. I am not too sure if the HMVC stuff your using will allow namespaces, but you can look at extending it that way. If not maybe rename both admin classes to something a bit more specific.

CodeIgniter controller gives 404 or it can't load the view file

I have the following issue with a simple controller in a CodeIgniter install.
In controllers/pages.php the Pages.php controller looks at the URL segments and load static files from folder and sub-folders inside the /views/pages directory.
Example:
If I have site.com/buy, then it would load buy.php form /views/pages
If the URL is site.com/buy/go, then it would load go.php from
/views/pages/buy, while site.com/buy would now be index.php from
/views/pages/buy
It was changed to add another sub-folder (e.g. site.com/buy/go/why from /views/pages/buy/go/why);
The controller:
class Pages extends CI_Controller {
public function __construct() {
parent::__construct();
$this->view();
}
private function view() {
$url_string = $this->uri->uri_string();
if (!file_exists(APPPATH . 'views/pages/'. $url_string. '/index.php')) {
if (!file_exists(APPPATH . 'views/pages/' . $url_string . '.php')) {
show_404();
} else {
$path = $url_string . '.php';
}
} else {
$path = $url_string . '/index.php';
}
$this->load->view('pages/' . $path);
}
The issue is that I get a 404 regardless of URL.
If I remove pages/ from $this->load->view it would throw another error: unable to load the file; but it does get the file right. (e.g. unable to load buy/go.php, while the URL issite.com/buy/go`).
I've just been playing around trying a few different things out to see what was going on.
I won't go into massive detail about everything I tried, but essentially there're only a couple things to change. Using the __construct() doesn't appear to work in the way you're trying to use it (ie simply passing all requests to one method). Instead, you'd need to either manually specify all the methods or use routes - so that's what I've done.
Adding the following line to your config/routes.php will redirect all requests to the view method:
$route['pages/(:any)'] = 'pages/view';
Once you've got the route in place there's no need for the __construct. The only thing left is to remove the pages/ part of the path, which you may have already done. I've tested the following code as far down as /pages/buy/go/test (3 levels), but in theory it should work the same at any nesting level.
class Pages extends CI_Controller {
public function view()
{
$url_string = $this->uri->uri_string();
if (!file_exists(APPPATH . 'views/'. $url_string. '/index.php'))
{
if (!file_exists(APPPATH . 'views/' . $url_string . '.php'))
{
show_404();
}
else
{
$path = $url_string . '.php';
}
}
else
{
$path = $url_string . '/index.php';
}
$this->load->view($path);
}
}
As a sidenote, you don't need to add the file extension when loading views unless it's something other than .php, though it doesn't matter either way.

Resources