- As a home owner
- when i provide address, price, subscription
- and i can drag and drop about 20 photos
- then a landing page will get created when i save it.
- hover.com
- try shopify business name generator
laravel new project-flyer
cd project-flyer/
git init
git add .
git commit -m "install laravel"
- create a new database named
projectflyer
- hook database to laravel
php artisan key:generate
npm install
- import bootstrap by uncommenting
@import
statement inresources/assets/sass/app.sass
// App/Html/routes.php
<?php
Route::get('/', function() {
return view('pages.home');
});
// Resources/views/layout.blade.php
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Project Flyer</title>
<link rel="stylesheet" href="/css/app.css">
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Project Flyer</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Home</a></li>
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<div class="container">
@yield('content')
</div>
</body>
</html>
// Resources/Views/pages/home.blade.php
@extends('layout')
@section('content')
<div class="jumbotron">
<div class="container">
<h1>Project Flyer</h1>
<p>This is a template for a simple marketing or informational website. It includes a large callout called a jumbotron and three supporting pieces of content. Use it as a starting point to create something more unique.</p>
<a href="flyers/create" class="btn btn-primary">Create a Flyer</a>
</div>
</div>
@stop
// Resources/assets/scss/app.scss
@import "node_modules/bootstrap-sass/assets/stylesheets/bootstrap";
@import "partials/forms";
body {
padding-top: 70px;
}
// resources/assets/scss/partials/forms.scss
.form-control {
height: 39px;
}
// App/Html/routes.php
...
Route::resource('flyers', FlyersController)
php artisan make:controller FlyersController
// App/Html/Controllers/FlyersController.php
...
public function create() {
return view('flyers.create');
}
// Resources/Views/flyers/create.blade.php
@extends('layout')
@section('content')
<h1>Selling Your Home?</h1>
@stop
// Resources/Views/flyers/create.blade.php
@extends('layout')
@section('content')
<h1>Selling Your Home?</h1>
<hr>
<div class="row">
<!-- Required if you are going to submit any files through a form -->
<form enctype="multipart/form-data" method="POST" action="/flyers" class="col-md-6">
@if(count($errors) > 0)
<div class="alert alert-danger">
<ul>
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
@include('flyers.form')
</form>
</div>
@stop
// resources/views/flyers/form.blade.php
@inject('countries' 'App\Http\Utilities\Country')
{{ csrf_field() }}
<div class="form-group">
<label for="street">Street:</label>
<input type="text" name="street" id="street" class="form-control" value="{{ old('street') }}" required/>
</div>
<div class="form-group">
<label for="city">City:</label>
<input type="text" name="city" id="city" class="form-control" value="{{ old('city') }}" required/>
</div>
<div class="form-group">
<label for="zip">Zip/Postal Code:</label>
<input type="text" name="zip" id="zip" class="form-control" value="{{ old('zip') }}" required />
</div>
<div class="form-group">
<label for="country">Country:</label>
<select id="country" name="country" class="form-control">
@foreach($countries::all() as $country => $code)
<option value="{{ $code }}">{{ $country }}</option>
@endforeach
</select>
</div>
<div class="form-group">
<label for="state">State:</label>
<input type="text" name="state" id="state" class="form-control" value="{{ old('state') }}" required/>
</div>
<hr>
<div class="form-group">
<label for="price">Sale Price:</label>
<input type="text" name="price" id="price" class="form-control" value="{{ old('price') }}" required/>
</div>
<div class="form-group">
<label for="description">Name:</label>
<textarea type="text" name="description" id="description" class="form-control" rows="10" required>
{{ old('description') }}
</textarea>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Create Flyer</button>
</div>
// App/Http/Utilities/Country.php
<?php
namesapce App\Http\Utilities;
class Country {
// take from https://gist.github.com/JeffreyWay/224de894c4d4e228d5af.js
protected static $countries = [ ... ]
public funtion all() {
return static::$countries;
}
}
php artisan make:migration create_flyers_table --create="flyers
// database/migrations/..._create_flyers_table.php
//...
$table->string('street');
$table->string('city', 40);
$table->string('zip', 10);
$table->string('state', 40);
$table->string('country', 40);
$table->integer('price');
$table->text('description');
//...
php artisan migrate make:migration create_flyer_photos_table --create="flyer_photos
// database/migrations/..._create_flyer_photos_table.php
//...
$table->integer('flyer_id')->unsigned();
$table->foreign('flyer_id')->references('id')->on('flyers')->onDelete('cascade');
$table->string('path');
//...
php artisan migrate
php artisan make:model Flyer
// database/factories/ModelFactory.php
<?php
//...
$factory->define(App\Flyer::class, function(faker\Generator $faker) {
return [
'street' => $faker->streetAddress
'city' => $faker->city,
'zip' => $faker->postcard,
'state' => $faker->state,
'country' => $faker->country,
'price' => $faker->numberBetween(10000, 5000000),
'description' => $faker->paragraph(3)
];
})
php artisan tinker
>>> factory('App\Flyer')->make();
>>> factory('App\Flyer')->make()->street;
// app/Flyer.php
//...
class Flyer extends Model {
protected $fillable = [
'street',
'city',
'state',
'country',
'zip',
'price',
'description'
];
public function photos() {
return $this->hasMany('App\Photo');
}
}
php artisan make:model Photo
//app/Photo.php
use Symfony\Component\HttpFoundation\File\UploadedFile;
//...
class Photo extends Model {
protected $table = 'flyer_photos';
protected $fillable = ['path'];
protected $baseDir = 'flyers/photos';
public function flyer() {
return $this->belongsTo('App\Flyer');
}
public static method fromForm(UploadedFile $file) {
$photo = new static;
$name = time() . $file->getClientOriginalName();
$photo->path = $photo->baseDir.'/'.$name;
$file->move($photo->baseDir, $name);
return $photo;
}
}
php artisan tinker
>>> $flyer = factory('App\Flyer')->make(); #creates a flyer in memory
>>> $flyer = factory('App\Flyer')->create(); #persists to database
>>> $flyer->photos()->create(['photo' => 'foo.jpg']); #creates a photo
>>> $flyer #displays the flyer
>>> $flyer->photos(); #displays the collection of photos
>>> App\Flyer::with('photos')->first(); #display flyer with photos
>>> App\Photo::all() #display all records in photo table
php artisan make:request FlyerRequest
// app/Http/Requests/FlyerRequest.php
//...
public function authorize() {
//does the user have authorization to make this request?
return true;
}
public function rules() {
return [
//what are the rules?
'street' => 'required',
'city' => 'required',
'zip' => 'required',
'country' => 'required',
'state' => 'required',
'price' => 'required|integer',
'description' => 'required'
];
}
// app/Http/Controllers/FlyersController.php
//...
use App\Http\Requests\FlyerRequest;
use App\Flyer;
//...
public function store(FlyerRequest $request) {
//persist a flyer
Flyer::create($request->all());
//flash messaging
//redirect to landing page
return redirect()->back();
}
//...
{
"autoload": {
"files": [
"app/helpers.php"
]
}
}
composer dump-autoload
// app/helpers.php
<?php
function flash($title = null, $message = null) {
$flash = app('App\Http\Flash');
if(func_num_args() == 0) {
return $flash;
}
return $flash->info($title, $message);
}
Download zip from t4t5.github.io/sweetalert. Copy both sweetalert-dev.js
and sweetalert.css
to resources/assets
:
- copy
sweetalert-dev.js
toresources/assets/js/libs
- copy
sweetalert.css
toresources/assets/css/libs
// gulpfile.js
//...
elixir(function(mix) {
mix.sass('app.scss')
.scripts([
'libs/sweetalert-dev.js'
], './public/js/libs.js')
.styles([
'libs/styles.css'
], './public/css/libs.css')
});
# compile js and css
gulp
// resources/views/welcome.blade.php
//...
// add in <head>
<link rel="stylesheet" href="/css/libs.css">
// add to end of <body>
<script src="/js/libs.js">
// as a test to see if it works (remove upon confirmation)
<script type="text/javascript">
swal({
title: "Error!",
text: "Here's my error message!",
type: "error",
confirmButtonText: "Cool"
});
</script>
// app/Http/Flash.php
<?php
namespace App\Http;
class Flash {
public function create($title, $message, $level, $key = 'flash_message') {
return session()->flash($key, [
'title' => $title,
'message' => $message,
'level' => $level,
]);
}
public function info($title, $message) {
return $this->create($title, $message, 'info');
}
public function success($title, $message) {
return $this->create($title, $message, 'success');
}
public function error($title, $message) {
return $this->create($title, $message, 'error');
}
public function overlay($title, $message, $level = 'success') {
return $this->create($title, $message, $level, 'flash_message_overlay');
}
}
// app/Http/Controllers/FlyersController.php
//...
public function store(FlyerRequest $request() {
Flyer::create($request->all());
flash()->success('Success!', 'Your flyer has been created.'); // add this line
return redirect()->back();
}
//...
public function create() {
flash()->overlay('Welcome Aboard', 'Thank you for signing up.'); // add this line
return view('flyers.create');
}
//...
// right after the last script tag
@include('flash')
//...
// resources/views/flash.blade.php
@if (session()->has('flash_message'))
<script>
swal({
title: "{{ session('flash_message.title') }}",
text: "{{ session('flash_message.message') }}",
type: "{{ session('flash_message.level' }}",
timer: 1700,
showConfirmButton: false
})
</script>
@endif
@if (session()->has('flash_message_overlay'))
<script>
swal({
title: "{{ session('flash_message_overlay.title') }}",
text: "{{ session('flash_message_overlay.message') }}",
type: "{{ session('flash_message_overlay.level' }}",
confirmButtonText: 'Okay',
})
</script>
@endif
php artisan tinker
>>> App\Flyer::first();
# the flyer should have been written to the database
// app/Http/routes.php
//...
// place below Route::resource('flyers', 'FlyersController'); statement
Route::get('{zip}/{street}', ['as' => 'store_photo_path', 'uses' => 'FlyersController@show']);
//...
// app/Http/Controllers/FlyersController.php
public function show($zip, $street) {
$flyer = Flyer::locatedAt($zip, $street);
return view('flyers.show', compact('flyer'));
}
// app/Flyer.php
//...
public static function LocatedAt($zip, $street) {
$street = str_replace('-', ' ', $street);
return static::where(compact('zip', 'street'))-first();
}
public function getPriceAttribute($price) {
return '$'.number_format($price);
}
public function addPhoto(Photo $photo) {
return $this->photos()->save($photo);
}
//...
Now when you navigate to
{zip}/{address}
url, you will receive the json response.
// resources/views/flyers/show.blade.php
@extend('layout')
@section('content')
<div class="row">
<div class="col-md-3">
<h1>{{ $flyer->street }}</h1>
<h2>{!! $flyer->price !!}</h2>
</div>
<hr>
<div class="description">{!! nl2br($flyer->description) !!}</div>
</div>
<div class="col-md-9">
//...
</div>
@stop
// tests/controllers/FlyersControllerTest.php
//...
/** @test */
class FlyersControllerTest extends Testcase {
public function it_shows_the_form_to_create_a_new_flyer() {
$this->visit('flyers/create');
}
}
// resources/views/layouts/layout.blade.php
<head>
//...
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/4.0.1/dropzone.css">
//...
</head>
<body>
//...
@yield('scripts.footer')
//...
</body>
// resources/views/flyers/show.blade.php
//...
@section('content')
<div class="row">
//...
<div class="col-md-9">
@foreach($flyer->photos as $photo)
<img src="{{ $photo->path }}" alt="">
@endforeach
</div>
</div>
<hr>
<h2>Add Your Photos</h2>
<form id="addPhotosForm"
action="{{route('store_photo_path', [
$flyer->zip,
$flyer->street
])}}"
method="POST"
class="dropzone">
{{ csrf_field() }}
</form>
@stop
@section('scripts.footer')
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/4.0.1/dropzone.js"></script>
<script>
Dropzone.options.addPhotosForm = {
paramName: 'photo',
maxFilesize: 3,
acceptedFiles: '.jpg, .jpeg, .png, .bmp',
accept:
}
</script>
@stop
// resources/assets/scss/app.scss
//...
img {
max-width: 100%;
}
// app/Http/routes.php
//...
Route::post('{zip}/{street}/photos', 'FlyersController@addPhoto');
// app/Http/Controllers/FlyersController.php
use App\Photo;
//...
public function addPhoto($zip, $street, Request $request) {
$this->validate($request, [
'photo' => 'require|mimes:jpg,jpeg,png,bmp';
]);
$photo = Photo::fromForm($request->file('photo'));
Flyer::locatedAt($zip, $street)->addPhoto($photo);
}