February 12, 2015 9:06 pm

How to Build a Marketplace with CakePHP 2 & Foundation 5/6

In the 4th part we have discussed about the OffersController and in this part we will finish OffersController module and move to the last part of this series of a very nice and helpful application so lets start part 5 of this series, you will get all tutorial source and demo after completion of this series.

How to Build a marketplace with CakePHP 2 & Foundation 5-6

We will finish our OffersController.

Now, we add a method that allows us to view offers only from particular categories:

public function view($offerName=null, $page=1) {
			if ($offerName&&is_int($page)) {

				$offerName= ucwords(str_replace("-", " ", $offerName));

			}
			$this->loadModel("Category");
			
			$cat=$this->Category->findByName($offerName);
			$offers=$this->Offer->findAllByCategoryId($cat['Category']['id'],
				array(),array('Offer.created'=>'desc'),
				20, $page
				);
			
			if ($offers) {

				$this->set("offers", $offers);
				$this->set("category", $cat['Category']['name']);
				$this->render();
			} 
			else {
				$this->redirect(array(
					'controller'=>'offers',
					'action'=>'index'
					));
			}
		

		}

We are converting the SEO friendly offerName to match the name of the category that is stored in our database and we are searching for a category with that name. Once we have it, we are querying the database for all offers in that category, ordering it and limiting 20 results.

Notice: findByColumnName returns one result whether findAllByColumnName returns all results that match the criteria.

We can use $this->Category->findById(1) which will return the row in the categories table that has the id of 1. Notice that the magic method is written in camelCase. We could also do $this->User->findAllByFullName(“Ivan”) which will return all records whose full_name is equal to Ivan.

$this->redirect takes an array of the controller and action we want the user to be redirected to and whenever the program executes that line – the user gets redirected.

$this->render() is used to render the view at the point where we are now. Alternatively, you could pass in a name of a view and it will render the View you want instead of the default one (which is located in ControllerName/methodName.ctp

For example, for the view() method of the OffersController the default View that is going to be rendered is located in …View/Offers/view.ctp

Here is the view() method’s View, which is nothing special and will not be commented.

<?php
$this->start("page_content");
?>
<br>
<br>
<div class="panel columns large-12 radius text-center">
	<h3><?php echo $category; ?></h3>
</div>
<br>

<?php foreach ($offers as $offer) : 

$images = explode("**", trim($offer["Offer"]['img']));

 ?>


<ul style="float:left;height: 700px;"class="medium-4 columns  pricing-table">
<li class="title"><?php echo $offer['Offer']['name']; ?></li>
<li class="price"><?php echo $offer['Offer']['price'];?>$</li>
<li class="description"><?php echo $offer['Offer']['description'];?></li>

<?php foreach ($images as $image) : ?>
<li class="bullet-item"><imgsrc="<?php echo $image;?>"
style="max-width: 150px; max-height: 250px;” alt="<?php echo $offer['Offer']['name'];?>"
></li>

<?php endforeach; ?>
<li class="bullet-item">Quantity offered:  <b><?php echo $offer['Offer']['qty'];?></b></li>
<li class="bullet-item">Offered since: <b><?php echo $offer['Offer']['created'];?></b></li>
<li class="bullet-item">Oferrer: <?php echo $offer['User']['full_name'];?></li>
<li class="cta-button"style="position: absolute;bottom:0"><aclass="buy button"href="/offers/buy/<?php echo $offer['Offer']['id'];?>">Buy <?php echo $offer["Offer"]['name']; ?> Now</a></li>
</ul>

<?php endforeach; ?>

<?php
$this->end();
?>

It is similar to the index() View of our OffersController so we could theoretically add the code inside an Element but we would not be going over that.

Here is the index view:

Notice that if there is a flash message (Session one-time message) we display it.

<?php $this->start("page_content"); ?>
<?php 
$flash = $this->Session->flash(); 

if (isset($flash) && !empty($flash)) : ?>
<div data-alert class="alert-box text-center">
<?php echo $flash; ?>
<a href="#"class="close">&times;</a>
</div>

<?php endif; ?>
<div class="panel text-center radius">
<h2>Recent Offers in All Categories </h2>
</div>
<?php

 foreach ($recentOffers as $offer) :
	
	$images = explode("**", trim($offer["Offer"]['img']));

 ?>
	


<ul style="float:left;height: 700px;"class="medium-4 columns  pricing-table">
<li class="title"><?php echo $offer['Offer']['name']; ?></li>
<li class="price"><?php echo $offer['Offer']['price'];?>$</li>
<li class="description"><?php echo $offer['Offer']['description'];?></li>

<?php foreach ($images as $image) : ?>
<li class="bullet-item"><img src="<?php echo $image;?>"
style="max-width: 150px; max-height: 250px;”alt="<?php echo $offer['Offer']['name'];?>"
></li>

<?php endforeach; ?>
<li class="bullet-item">Quantity offered:  <b><?php echo $offer['Offer']['qty'];?></b></li>
<li class="bullet-item">Offered since: <b><?php echo $offer['Offer']['created'];?></b></li>
<li class="bullet-item">Oferrer: <?php echo $offer['User']['full_name'];?></li>
<li class="cta-button"style="position: absolute;bottom:0"><aclass="buy button"href="/offers/buy/<?php echo $offer['Offer']['id'];?>">Buy <?php echo $offer["Offer"]['name']; ?> Now</a></li>
</ul>

<?php

 endforeach; ?>

<?php $this->end(); ?>

Next is our add method which will be called when an user adds an offer.

You can see that if the request method is not POST we are not doing anything – we just render the appropriate View.

However, if the request method is POST, we are adding the id of the user to all of the POST data (if we just added it to the form it could have been easily manipulated) and saving the image to the /img/offers/USER_ID/ORIGINAL_IMG_NAME folder inside webroot. Webroot is the directory where all of your publicly accessible content will go (such as css files, js files, images).

public function add() {
		if ($this->request->is("post")) {
			
		$this->request->data['Offer']['user_id'] =$this->Auth->user("id");
		$img_name=$this->request->data['Offer']['img']['name'];
		$img=$this->request->data['Offer']['img']['tmp_name'];
		$pathDB="/img/offers/".$this->Auth->user("id") ."/$img_name";
		$path= WWW_ROOT ."img/offers/".$this->Auth->user("id") ."/$img_name";
		if (!is_dir( WWW_ROOT ."img/offers/".$this->Auth->user("id"))) {
			mkdir(WWW_ROOT ."img/offers/".$this->Auth->user("id"));
		}
		$this->request->data['Offer']['img'] =$pathDB;
		if (move_uploaded_file($img, $path)) {
			$this->Offer->create();
			if ($this->Offer->save($this->request->data)) {
				$this->Session->setFlash("Offer added successfully");
				$this->redirect(array(
						'controller'=>'offers',
						'action'=>'index'
					));
				}
			}
		}
	}

 

If the images have been moved to the user’s images folder and the offer has been saved to the database (notice we added the user id and changed the img element to contain the full path to the image in the data the user provided instead of the image itself) we redirect. But before that, we set a message that will be stored in the user’s session and will be deleted whenever we use it.

To set such a message, we use $this->Session->setFlash(“message”);

To access it we usually save it to a variable and display it whenever we want in the page – we use $this->Session->flash() to get it.

The add View will teach you the basics of CakePHP’s Form helper.

We use $this->Form->create(modelName, options) and $this->Form->input(‘inputName (usually matches our table columns)’, options)

The label option sets a label for the particular input, we can pass whatever HTML options we want. For example ‘type’ => ‘file’ or ‘required’ => ‘required’ or ‘min’ => 1

We can also give an ‘options’ key inside our options array which will hold an array of values that will be used for a select element. See how we have done this below. We set an array in which the keys are the ids (we will store the ids in the database) and the name of the categories as a value (which will be displayed to the user).

We can also use $this->Form->textarea which takes a name (usually our table’s column name) and an array of options.

<?php

$this->start("page_content"); 
?>
<br>
<br>
<div class="columns large-8 large-offset-2">
<?php
echo $this->Form->create('Offer',array(
	'action' => 'add',
	'controller' => 'offers',
	'type' => 'file'
	));

echo $this->Form->input('name',
	array(
		'label' => 'Product Name:',
		'required' => 'required'
		)
	);
	$cat = array();
	foreach($categories as $category) {
		if (trim($category['Category']['name']) !== "") {
		$cat[$category['Category']['id']] =  $category['Category']['name'];
		}
	}
	
echo $this->Form->input('category_id',
	array(
		'label' => 'Category:',
		'options' => $cat,
		'required' => 'required',
		'empty' => "Choose a Category"
		)
	);

echo $this->Form->input('price',
	array(
		'label' => 'Price Per Product:',
		'required' => 'required',
	
		)
	);

echo $this->Form->input('qty',
	array(
		'label' => 'Quantity available:',
		'type' => 'number',
		'required' => 'required',
		'min' => '1'
		)
	);
echo "Product Description:";
echo $this->Form->textarea('description',
	array(
		'placeholder' => 'Description',
		'required' => 'required',


		)
	);

echo $this->Form->file('img',
	array(
		'label' => 'Product Image:',
		'type' => 'file',
		'required' => 'required',
		
		)
	);

echo $this->Form->end(
	array(
		'label' => 'Add Offer',
		'class' => 'button  small radius'
		));



?>

</div>
<?php

$this->end();

?>

Part 1: How to Build a Marketplace with CakePHP 2 & Foundation 1/6

Part 2: How to Build a Marketplace with CakePHP 2 & Foundation 2/6

Part 3: How to Build a Marketplace with CakePHP 2 & Foundation 3/6

Part 4: How to Build a Marketplace with CakePHP 2 & Foundation 4/6

Part 5: How to Build a Marketplace with CakePHP 2 & Foundation 5/6

Part 6: How to Build a Marketplace with CakePHP 2 & Foundation 6/6

Marketplace with CakePHP 2 & Foundation Demo & Download

Author Ivan Dimov

Ivan is a student of IT, a freelance web designer/developer and a tech writer. He deals with both front-end and back-end stuff. Whenever he is not in front of an Internet-enabled device he is probably reading a book or traveling. You can find more about him at: http://www.dimoff.biz. facebook, twitter


Tutorial Categories:

Leave a Reply

Your email address will not be published. Required fields are marked *