Jump to content

Import CSV from API


Manaus
 Share

Recommended Posts

Greetings Manaus,

As luck would have it, I just completed a project where the client needed to have a form on the front end where he can upload a CSV file and have it create pages.

Using ProcessWire, I put together a system that does the following:

1. Presents the visitor with a simple form with a "title" and an "upload" field

2. Creates a parent page with the title = "title"

3. Uploads and saves the CSV file to the parent page

4. Opens the CSV file using PHP's native fopen

5. Reads the rows of the opened CSV file using PHP's native fgetcsv function; a simple counter skips the first row (which is assumed to be a header row)

6. Creates children of the "title" page, each with the name of the data in first column of each row

7. Presents a "success" message when it works.

Your needs might be different, so just vary the code as needed, or post a follow-up question for more details.

Here's the code (with my documentation added):
 

<div class="chart_form_box">
	<?php
	if ($input->post->title)  // Confirm that a proper submission happened: if the form submission at least has a title, use the field entries to create a new parent page.
	{
	// Set a temporary upload location where the submitted "csv_import" file is stored during form processing (will be removed at the end of the process).
	$upload_path = $config->paths->assets . "files/csv_uploads/"; // This folder must exist in the directory structure.
			
	// New wire upload routine for the CSV file.
	$csv_upload = new WireUpload('csv_upload'); // Reference field name in HTML form that uploads the CSV file.
	$csv_upload->setMaxFiles(1);  // Allow only 1 CSV file upload.
	$csv_upload->setOverwrite(false);  // Rename any current files, instead of overwriting them.
	$csv_upload->setDestinationPath($upload_path); // Use the temporary location set above to place the CSV upload.
	$csv_upload->setValidExtensions(array('csv')); // Only allow CSV files.
	$csv_uploads = $csv_upload->execute();  // Execute CSV file upload.
	
	// First round of page creation (for the parent page, created from a title and a CSV file upload).
	// Set up submissions in the ProcessWire page tree.
	$np = new Page(); // create new page object.
	$np->template = $templates->get("windsor_parent"); // Set template for pages created from form submissions.
	$np->parent = $pages->get("/windsor-list/"); // Set parent for pages created from form submissions.
												
	$np->of(false);
	
	// Sanitize form submissions and store the submissions as values in the template fields for the new parent page.
	$np->title = $sanitizer->text($input->post->title);
	$np->name = $sanitizer->pageName($input->post->title, true); // Create a URL-friendly "name" based on the title.
	
	// Save/create the new parent page.
	$np->save();
	
	// Run the file upload for "csv_upload."
	foreach($csv_uploads as $csv_upload) // Loop through the CSV uploads, even if there is just one.
	{
		$pathname = $upload_path . $csv_upload; // Store the temporary CSV file in the path dedicated to that purpose.
		$np->csv_upload->add($pathname); // Store the uploaded CSV file in the "csv_upload" field of the template.
		$np->message("Added file: $csv_upload"); // Include a message regarding the file that was uploaded.
		unlink($pathname); // Remove the file from the temporary folder since it is no longer needed after it is uploaded.
	}
			
	$np->save();  // Save page again after CSV file upload
			
		// Beginning of routine to save children of the page saved above: derived from the rows in the CSV file.
		if (($objCSV = fopen("http://www.pwplayground.com/site/assets/files/$np->id/$np->csv_upload", "r")) !== FALSE) // Open the uploaded CSV file that was saved above.
		{ ?>
			
			<!-- Create a list of the rows in the CSV file -->
			<?php  // Loop through the rows in the CSV file using PHP's fgetcsv function, with the goal of placing the data in each row of the CSV file into fields in our "windsor_child" template.
					
			$i = 0; // Set up a counter variable. This is used to keep track of iterations that will correspond to rows parsed in the CSV file. We will use this later to skip the first row, which is a header row.
					
			while (($objArr = fgetcsv($objCSV)) !== FALSE) // Instruct fgetcsv to add to the $objarr as long as there is a row to read.
			{
					if( $i >= 1 ) // Only run the process beginning with the 2nd row, thereby skipping the header row.
	        		{
	        			// Beginning of routine to save child pages based on the rows in the uploaded CSV file.
					$np2 = new Page(); // create new page object
					$np2->template = $templates->get("windsor_child"); // Set template for child pages.
					$np2->parent = $pages->get("/windsor-list/$np->name/"); // Set parent for child pages to be the page created above.					
					$np2->of(false);  // Set output formatting off during the page-creation process.

					// Sanitize the rows of the CSV files, just in case someone uploads something evil, then store the values in each row into the template fields for the new page.
					$np2->title = $sanitizer->text($objArr[1]);
					$np2->name = $sanitizer->pageName($np2->title, true); // Create a URL-friendly "name" based on the title.
					$np2->windsor_count = $sanitizer->text($objArr[0]); // Store the first column of each row in the "windsor_count" field of the template.
					$np2->windsor_name = $sanitizer->text($objArr[1]); // Store the second column of each row in the "windsor_name" field of the template.
						
					// Save/create the new child page.
					$np2->save();
					// End of routine to save child pages based on the rows in the uploaded CSV file.
				}

			$i++; // Move the counter variable up one tick with each iteration.
			} ?>
		<?php
		}
		fclose($objCSV);
		// End of routine to save children of the page saved above. These are derived from the rows in the CSV file.
		?>

	<!-- If uploading the CSV file, and creating the new parent chart page and children pages were all successful, then: (1) Confirming success; (2) Present option to jump to the newly created page; (3) Present option to create another new page. -->
	<div class="admin_success_box">
		<p>SUCCESSFULLY CREATED A NEW CHART PAGE CALLED "<?php echo $np->title ?>"</p>
		<p><a href="<?php echo $np->url?>">VIEW THE NEW CHART PAGE </a>-- or --<a href="<?php echo $page->url ?>"> CREATE ANOTHER CHART PAGE</a></p>
	</div>
	
<?php
} // / if ($input->post->title)
?>

<!-- Actual entry form that allows the user to set a title and upload a CSV file -->
<h1>Use the Form Below to Create a New Parent and Children from a CSV</h1> 
<form action="<?php echo $page->url ?>" method="post" enctype="multipart/form-data">
	<p><label class="create_chart_field_label" for="title">Title</label>
	<input type="text" class="create_chart_long1" name="title" value="<?php echo $input->post->title ?>"></p>
		
	<p>Upload 1 CSV File:
	<input type="file" class="create_chart_field1" name="csv_upload" /></p>

	<button class="admin_submit" type="submit" name="submit">CREATE CHART!</button>
</form>
</div> <!-- / chart_form_box -->

My apologies for the formatting. (Also, the "chart" references are specific to my particular project.)

As you can see, much of this involves using ProcessWire's API to create pages, but with a few extra steps for the CSV material.

Thanks,

Matthew

  • Like 5
Link to comment
Share on other sites

I'm not aware of some plug-and-play frontend examples*, but it's definitely possible.

http://php.net/manual/en/function.fgetcsv.php

If you're familiar with the PW API, then creating pages, or updating existing pages / fields should not be too complex.

* there's the excellent "import from CSV" module, but that only runs from within the PW backend.

http://modules.processwire.com/modules/import-pages-csv/

Link to comment
Share on other sites

 I need to make a page where the user uploads a csv file and then values are added to some page

This is a bit ambiguous. Do you want to create a new page for each CSV import? Or do you want to update existing pages (= update fields for already existing PW pages)?

Link to comment
Share on other sites

Thanks so much Matthew for publishing the code

Thanks Dragan

Well I have a Project $page which is, say "Project Bluemoon". I need to add users to this project, and since they might be dozens, the client asked me to make a form. Upon uploading the csv rows, this is the logic:

if (user exists) {

  add user to Project

} else {

  add user to $users;

  add user to Project;

}

Each Csv row contains username, email, password, project_code

That's it... !

Thanks!!

Link to comment
Share on other sites

Greetings Manaus,

Then you can use the code I posted, but specify more fields.

For example, where I have this, which specifies two fields in my template called "windsor_count" and "windsor_name":

$np2->windsor_count = $sanitizer->text($objArr[0]); // Store the first column of each row in the "windsor_count" field of the template.
$np2->windsor_name = $sanitizer->text($objArr[1]); // Store the second column of each row in the "windsor_name" field of the template.

You would have four fields: username, email, password, and project_code, and they would reference [0] through [3] in your variable storing the array ($objArr in my example).

Thanks,

Matthew

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...