Все пишут про то, как распарсить xls, только вот самое узкое место в процессе совсем не в том месте.
Проблемы начинаются, когда надо с помощью activeRecord просохранять несколько тысяч моделей. Если делать это в цикле, как предлагают выше, то в один прекрасный момент сервер вам скажет пару ласковых и скинет операцию либо по таймауту, либо по памяти, даже если лимиты задрать.
Я использую два принципиально разных варианта:
1) В операции импорта генерировать массив с полями модели и отдавать его в SQL-запрос, в обход activeRecord.
Просто вставляем в базу кучу записей, при повторе ключа - обновляем. Он довольно быстрый, но мне не нравится, так как не очень удобно работать со сложными структурами. Ну и теряем при этом такие вещи, как обработку behaviors, валидацию полей из rules модели, события и т.д. Конечно, если все это очень надо, то это можно вручную вызвать, но тогда и смысла в варианте не много остается.
$db = Yii::$app->db;
$sql = $db->queryBuilder->batchInsert(self::tableName(), $fields, $fullarray);
$product_insert_count = $db->createCommand($sql . ' ON DUPLICATE KEY UPDATE name = VALUES(name), group_id = VALUES(group_id), manufacturer = VALUES(manufacturer), fullname = VALUES(fullname), code = VALUES(code)')->execute(); //Возвращает количество вставленных записей
2) Очереди. Сейчас в основном этим вариантом пользуюсь.
https://github.com/yiisoft/yii2-queue
Парсим файл, для обработки каждого товара создаем задание, в котором проводим все нужные операции (проверку на необходимость обновления, обновление или создание новой модели и т.д.) и добавляем это задание в очередь. После формирования очереди консольной командой запускаю выполнение очереди.