Path cannot be empty error

Solved
kaprinkey1 ・

Jan 27th, 2024 03:10 PM

Hey Bobby or whomever,

I know that I probably have made a lot questions to this point and that's my bad. I was just starting out and had much to learn.

Since then, I have fallen in love with laravel and use it for everything. I have used Tails and Wave on several occasions and still do.

As Bobby already knows I am working on a advertiser publishing website. Right now I am working on the mass upload of stores via a CSV file given by Commission Junction. Currently I am trying to store, process and then insert the data into the stores table.

The process works up until I click submit CSV File. I keep getting 'path cannot be empty' error, no matter how I store it or what package I use to process the CSV file which is Laravel Excel by MaatWebsite or Spartner.

The package works just fine and I was able to get my controller code down to a few lines.

<?php

namespace App\Http\Controllers;

use App\Imports\StoresImport;
use Illuminate\Http\Request;
use League\Csv\SyntaxError;
use League\Csv\UnavailableStream;
use Maatwebsite\Excel\Facades\Excel;


class CsvController extends Controller
{

    /**
     * @throws UnavailableStream
     * @throws SyntaxError
     */

    public function importFromCsv(Request $request)
    {
        $data = $request->all();
        Excel::import(new StoresImport, request()->file('csv_file'));

        return redirect()->route('stores.index')->with('success', 'CSV file uploaded successfully');

    }

    private function convertToBoolean(mixed $value)
    {
        $normalizedValue = strtolower(trim($value));
        return in_array($normalizedValue, ['yes', 'true', 'allowed', '1', '0', 'no', 'false', 'denied', 'null']);
    }

    function showUploadForm()
    {
        return view('themes.tailwind.advertisers.upload-csv');
    }
}

However, even with this package I still get the error 'path cannot be empty'? Do you have any idea what could cause this and how I can get past it?

There is an imports file I made that maps out the CSV file to the stores DB tables using the code below and provided when you make the import class and I specified the store model which contains all the columns from the csv header row. I was defining the header row using offset but have not added that back after installing the Laravel Excel package.

return new Store(
my mapped data
);

I assumed the package I installed processed the file for you? Do I need my own logic to process the CSV file?

The form used to upload the csv file does have csv_file as the name so I do not understand what I am doing wrong?

I do have a public disk defined in filesystems.php that points to storage_path('app\csv') which is where the file should be uploaded and to test this I added the file myself to the directory and it still tells me 'path cannot be empty' even though I had written the controller to process the file from a set location.

Is the storage directory not writable? Is that what I am doing wrong? Should it write to the public directory instead?

kaprinkey1 ・

Jan 29th, 2024 06:13 AM

I got past this already.

Now I am stuck on it telling me the array keys do not exist even though they clearly do and at this point I am using a form to upload the csv to the session. For whatever reason it cannot find the file. I assume it's a permissions issue with laragon.

bobbyiliev ・

Jan 29th, 2024 06:29 AM

Hey!

You would need to do some debugging, here is how I would go about doing this.

First things first, let's confirm whether the file is being uploaded correctly and the application is receiving it as expected.

  1. Check the File Input Name: Ensure the name of the file input in your HTML form matches what you're trying to access in your controller. It should look like this:

    <input type="file" name="csv_file">
    
  2. Form Attribute: Double-check your form tag includes enctype="multipart/form-data":

    <form method="POST" action="/your-route" enctype="multipart/form-data">
    
  3. Debugging with dd(): Let’s use Laravel’s dd() (Dump and Die) function to check what’s coming through in the request. In your controller method, you can add this line to see what the request contains:

    public function importFromCsv(Request $request)
    {
        dd($request->all());
        // Rest of your code...
    }
    

    After submitting the form, you should see an array of the submitted data, including the CSV file details.

  4. Check Uploaded File: Once you confirm the file is in the request, check if it's properly uploaded using dd():

    public function importFromCsv(Request $request)
    {
        dd($request->file('csv_file'));
        // Rest of your code...
    }
    

    This will show you the uploaded file object or null if the file is not there.

Handling the File Path

If the file is being uploaded correctly, let’s move on to handling its path.

  1. Storing the File: Try storing the file first and then processing it. Here's an example:

    public function importFromCsv(Request $request)
    {
        $file = $request->file('csv_file');
        $path = $file->store('csv');
    
        dd($path); // This will show the path where the file is stored
    
        // Now use this path for the Excel import
        Excel::import(new StoresImport, storage_path('app/'.$path));
    
        // Rest of your code...
    }
    

    In this code, we’re storing the file in the 'csv' directory inside the 'storage/app' folder and then using that path to import the file.

  2. Directory Permissions: If the file is not being stored, check the permissions of the 'storage/app/csv' directory. It should be writable by the web server.

Addressing the Array Keys Error

For the array keys error, here’s a quick check:

  1. Inspecting the CSV Data: After importing, you might want to inspect the data to ensure it's being read correctly:

    // Inside your StoresImport class
    public function model(array $row)
    {
        dd($row); // This will show each row's data
    
        // Rest of your mapping code...
    }
    

    This will help you see if the keys you're expecting are actually there in the data.

With these debugging steps, you should be able to pinpoint where the issue lies.

Let me know how it goes.

kaprinkey1 ・

Jan 29th, 2024 06:45 AM

Thank you Bobby. I will debug today. I'll let you know how it goes.

bobbyiliev ・

Jan 29th, 2024 07:45 AM

Sounds good! Let me know how it goes and feel free to share the debug messages here as long as there is no sensitive information.

kaprinkey1 ・

Jan 29th, 2024 02:08 PM

Hey Bobby.

I just added the dd($request->file('csv_file')); and it does not show the file or data within the file? Quite honestly, I have used the DD statement before and I have never seen it return this data?

This part concerns me as you can see a couple of them are set to false. Could be the problem.

writable: true
  readable: true
  executable: false
  file: true
  dir: false
  link: false

Screenshot (1021).png

UPDATE: I spent some time last night trying to figure out what the true false statements meant and did not find an answer.

I think I found the issue. I never grab the file from the temp directory where it's stored after upload.

I want to store the file so I will use this instead but I tried the code below and it tells me the path cannot be empty? Of course I changed the path to the real path. Let ask you this, am I able to store the file at storage/app/public/csv and the grab and process it?

$path = $request->file('csv_file')->store('path/to/save');
$content = Storage::get($path);
kaprinkey1 ・

Jan 31st, 2024 03:38 PM

・

Best Answer

Bobby,

I think I found the issue. The array keys are all lowercase and I had them differently in the imports file. The screenshot I posted above showing the temp directory, that is because I am using 2 separate controllers for this: 1 storesimports controller, 1 csvcontroller. I was using the importFromCsv in the route. I add a DD header row statement to the StoresImport controller and now when I submit the file it shows me all the header rows. I think this was because it wanted me to use the StoresImport controller to be process the file, not the csvcontroller lol. Which would be why it showed the temp directory bc now it also stores the file in the directory I specified but does not insert into the DB bc of the array keys issue.

I think once I fix the array keys issue this will work.

Thank you for the help. You reminding me about the DD statement assisted in helping me find the issue. I also appreciate all the times you were there to help me debug and fix issues. If it weren't for you I'd still be stuck on other issues lol.

UPDATE: Just as I suspected, the array keys were off. In the controller they were first letter uppercase but when I ran dd(array_keys($row)); all the array keys were lowercase. It works just fine now. I also put an if-else statement in the CSVController.

<?php

namespace App\Imports;

use App\Models\Category;
use App\Models\Store;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;


class StoresImport implements ToModel, WithHeadingRow
{
    /**
     * @param array $row
     *
     * @return Model|Store
     */
    public function model(array $row): Model|Store
    {

        $existingStore = Store::where('id', $row['id'])->exists();
        if (!$existingStore) {
            return Store::updateOrCreate([
                'advertiser_id' => $row['advertiser_id'],
                'program_name' => $row['program_name'],
                'three_month_epc' => $row['three_month_epc'],
                'seven_day_epc' => $row['seven_day_epc'],
                'network_ranking' => $row['network_ranking'],
                'date_created' => $row(Carbon::create($row['date_created'])),
                'has_products' => $this->convertToBoolean($row['has_products']),
                'country' => $row['country'],
                'advertiser_currency' => $row['advertiser_currency'],
                'min_itemlevelfixed_lead_commission' => $row['min_itemlevelfixed_lead_commission'],
                'max_itemlevelfixed_lead_commission' => $row['max_itemlevelfixed_lead_commission'],
                'min_itemlevelfixed_sale_commission' => $row['min_itemlevelfixed_sale_commission'],
                'max_itemlevelfixed_sale_commission' => $row['max_itemlevelfixed_sale_commission'],
                'min_percent_lead_commission' => $row['min_percent_lead_commission'],
                'max_percent_lead_commission' => $row['max_percent_lead_commission'],
                'min_percent_sale_commission' => $row['min_percent_sale_commission'],
                'max_percent_sale_commission' => $row['max_percent_sale_commission'],
                'max_orderlevelfixed_lead_commission' => $row['max_orderlevelfixed_lead_commission'],
                'min_orderlevelfixed_lead_commission' => $row['min_orderlevelfixed_lead_commission'],
                'max_orderlevelfixed_sale_commission' => $row['max_orderlevelfixed_sale_commission'],
                'min_orderlevelfixed_sale_commission' => $row['min_orderlevelfixed_sale_commission'],
                'max_viewthrough_itemlevelfixed_lead_commission' => $row['max_viewthrough_itemlevelfixed_lead_commission'],
                'min_viewthrough_itemlevelfixed_lead_commission' => $row['min_viewthrough_itemlevelfixed_lead_commission'],
                'max_viewthrough_percent_lead_commission' => $row['max_viewthrough_percent_lead_commission'],
                'min_viewthrough_percent_lead_commission' => $row['min_viewthrough_percent_lead_commission'],
                'max_viewthrough_itemlevelfixed_sale_commission' => $row['max_viewthrough_itemlevelfixed_sale_commission'],
                'min_viewthrough_itemlevelfixed_sale_commission' => $row['min_viewthrough_itemlevelfixed_sale_commission'],
                'max_viewthrough_percent_sale_commission' => $row['max_viewthrough_percent_sale_commission'],
                'min_viewthrough_percent_sale_commission' => $row['min_viewthrough_percent_sale_commission'],
                'max_viewthrough_orderlevelfixed_lead_commission' => $row['max_viewthrough_orderlevelfixed_lead_commission'],
                'min_viewthrough_orderlevelfixed_lead_commission' => $row['min_viewthrough_orderlevelfixed_lead_commission'],
                'max_viewthrough_orderlevelfixed_sale_commission' => $row['max_viewthrough_orderlevelfixed_sale_commission'],
                'min_viewthrough_orderlevelfixed_sale_commission' => $row['min_viewthrough_orderlevelfixed_sale_commission'],
                'fixed_click_commission' => $row['fixed_click_commission'],
                'performance_incentive' => $this->convertToBoolean($row['performance_incentive']),
                'search_campaigns_protected_sem_bidding_keywords' => $row['search_campaigns_protected_sem_bidding_keywords'],
                'negative_matching_for_protected_keywords' => $row['negative_matching_for_protected_keywords'],
                'search_campaigns_non_compete_sem_bidding_keywords' => $row['search_campaigns_non_compete_sem_bidding_keywords'],
                'search_campaigns_recommended_sem_bidding_keywords' => $row['search_campaigns_recommended_sem_bidding_keywords'],
                'search_campaigns_prohibited_sem_display_url_content' => $row['search_campaigns_prohibited_sem_display_url_content'],
                'search_campaigns_limited_use_sem_display_url_content' => $row['search_campaigns_limited_use_sem_display_url_content'],
                'search_campaigns_prohibited_sem_ad_copy_content' => $row['search_campaigns_prohibited_sem_ad_copy_content'],
                'search_campaigns_limited_use_sem_ad_copy_content' => $row['search_campaigns_limited_use_sem_ad_copy_content'],
                'search_campaigns_direct_linking' => $this->convertToBoolean($row['search_campaigns_direct_linking']),
                'search_campaigns_authorized_search_engines' => $row['search_campaigns_authorized_search_engines'],
                'search_campaigns_special_instructions_for_search_marketing' => $row['search_campaigns_special_instructions_for_search_marketing'],
                'web_site_prohibited_web_site_domain_keywords' => $row['web_site_prohibited_web_site_domain_keywords'],
                'web_site_prohibited_web_site_url_keywords' => $row['web_site_prohibited_web_site_url_keywords'],
                'web_site_prohibited_web_site_content' => $row['web_site_prohibited_web_site_content'],
                'web_site_unacceptable_web_sites' => $row['web_site_unacceptable_web_sites'],
                'web_site_use_of_logos_and_trademarks_in_web_sites' => $row['web_site_use_of_logos_and_trademarks_in_web_sites'],
                'incentivized_traffic' => $this->convertToBoolean($row['incentivized_traffic']),
                'email' => $this->convertToBoolean($row['email']),
                'software' => $this->convertToBoolean($row['software']),
                'sub_affiliates' => $this->convertToBoolean($row['sub_affiliates']),
                'social_media' => $this->convertToBoolean($row['social_media']),
                'coupons_and_promotional_codes' => $row['coupons_and_promotional_codes'],
                'non_commissionable_items' => $row['non_commissionable_items'],
                'viewthrough_campaigns' => $row['viewthrough_campaigns'],
                'miscellaneous_special_instructions ' => $row['miscellaneous_special_instructions'],

            ]);
        }
       return view('themes.tailwind.advertisers.upload-csv');
    }


    public function headingRow(): int
    {
        return 1; // or any other row number that contains the headers
    }


    public function convertToBoolean(mixed $value): bool
    {
        $normalizedValue = strtolower(trim($value));
        return in_array($normalizedValue, ['yes', 'true', 'allowed', '1', '0', 'no', 'false', 'denied', 'null']);
    }

}

<?php

namespace App\Http\Controllers;

use App\Imports\StoresImport;


use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use League\Csv\SyntaxError;
use League\Csv\UnavailableStream;
use Maatwebsite\Excel\Facades\Excel;
use Maatwebsite\Excel\Validators\ValidationException;


class CsvController extends Controller
{

    /**
     * @throws UnavailableStream
     * @throws SyntaxError
     */


    public function importFromCsv(Request $request)
    {
        // Validate the request

        // Retrieve the file from the request
        $file = $request->file('csv_file');

        // Check if the file was uploaded
        if ($file) {
            // Store the file using the 'public' disk (or any disk configured in config/filesystems.php)
            $filePath = $file->store('csv', 'public');

            // Import the file using Maatwebsite Excel
            Excel::import(new StoresImport, request()->file('csv_file'));

            // Redirect with success message
            return back()->with('success', 'File has been uploaded and imported.');
        } else {
            // Redirect with error message if file wasn't uploaded
            return back()->with('error', 'No file was uploaded.');
        }
    }

    function showUploadForm()
    {
        return view('themes.tailwind.advertisers.upload-csv');
    }
}

I just need to add some code to process the category column from the spreadsheet and I am gucci.

Thank you for the help Bobby, truly appreciate it. Developers should support each other more often I think. I know a few guys who refuse to even ask another developer to help them. I think that is just not smart at all. How are you supposed to learn anything lol.

bobbyiliev ・

Feb 1st, 2024 02:05 AM

Hey!

That is great! I'm glad to hear you're making progress with your spreadsheet processing. Adding code to handle the category column sounds like a solid step forward. If you need any tips or run into any hurdles with that, feel free to reach out.

I fully agree with you on the importance of developers supporting each other. The tech world is vast and constantly evolving, making it virtually impossible for anyone to know everything. Sharing knowledge, experiences, and even challenges not only helps us grow as professionals but also fosters a more collaborative and innovative community. It's all about lifting each other up and learning from one another. After all, some of the best solutions and ideas come from collaboration.

Keep the questions coming, and never hesitate to lend a hand when you can. That's how we all get better, together!

Report
1