Laravelред рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░реЗрдВ, рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдВ рдФрд░ рдмрдирд╛рдПрдВ

рддреЛ, рдЖрдкрдХреЛ рд▓рд╛рд░рд╡реЗрд▓ рдврд╛рдВрдЪреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдиреЗ рдпрд╛ рдЬрд╛рдирдиреЗ рдХреА рдЗрдЪреНрдЫрд╛ рд╣реИред

рдпрджрд┐ рдЖрдк рдЕрдиреНрдп PHP рдлреНрд░реЗрдорд╡рд░реНрдХ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реИрдВ - рдпрд╣ рдЖрдкрдХреЗ рд▓рд┐рдП рдореБрд╢реНрдХрд┐рд▓ рдирд╣реАрдВ рд╣реЛрдЧрд╛, рдпрджрд┐ рдирд╣реАрдВ - рдпрд╣ рдкрд╣рд▓реА рд░реВрдкрд░реЗрдЦрд╛ рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрддреНрдХреГрд╖реНрдЯ рд╡рд┐рдХрд▓реНрдк рд╣реИред

рд▓рд╛рд░рд╡реЗрд▓ - рдХрд╛рд░реАрдЧрд░реЛрдВ рдХреЗ рд▓рд┐рдП рдкреАрдПрдЪрдкреА рдлреНрд░реЗрдорд╡рд░реНрдХ!

рд▓реЗрдЦ рдмрд╣реБрдд рдмрдбрд╝рд╛ рд╣реИред рдореИрдВ рд╕рдкреНрддрд╛рд╣рд╛рдВрдд рдХреЗ рджреМрд░рд╛рди рдЗрд╕реЗ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдкрдврд╝рдиреЗ рдХреА рд╕рд▓рд╛рд╣ рджреЗрддрд╛ рд╣реВрдВред

рдЖрд▓рд╕реА рдХреЗ рд▓рд┐рдП:
GitHub
рдЖрд╡реЗрджрди



рд╕реНрдерд╛рдкрдирд╛


рд▓рд╛рд░рд╡реЗрд▓ рдХреЛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдореЗрдВ рд╕рдВрдЧреАрддрдХрд╛рд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ
рд╕рдВрдЧреАрддрдХрд╛рд░ PHP рдореЗрдВ рдПрдХ рдирд┐рд░реНрднрд░рддрд╛ рдкреНрд░рдмрдВрдзрди рдЙрдкрдХрд░рдг рд╣реИред рдпрд╣ рдЖрдкрдХреЛ рдПрдХ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдирд┐рд░реНрднрд░ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреА рдШреЛрд╖рдгрд╛ рдХрд░рдиреЗ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдПрдХ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред
- рд╕рдВрдЧреАрддрдХрд╛рд░

рдкрд░реНрдпрд╛рд╡рд░рдг *nix рдкрд░реНрдпрд╛рд╡рд░рдг рдореЗрдВ рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ (рд╕рд╛рдЗрдЯ рдкрд░ рд╡рд┐рдВрдбреЛрдЬ рдкрд░ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдореИрдиреБрдЕрд▓ рднреА рд╣реИ, рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдЖрдкрдХреЛ рдПрдХ рд╕рд░реНрд╡рд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, WAMP рдФрд░ Git )ред

рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдмрд╣реБрдд рд╕рд╛рдл рдУрдПрд╕ рд╣реИред рдлрд┐рд░ рдЯрд░реНрдорд┐рдирд▓ рдЦреЛрд▓реЗрдВ рдФрд░ рдЗрди рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдХреЙрдкреА рдФрд░ рдкреЗрд╕реНрдЯ рдХрд░реЗрдВ

 #    sudo apt-get update sudo apt-get install -y build-essential sudo apt-get install -y python-software-properties #    php 5.5 sudo add-apt-repository ppa:ondrej/php5 sudo apt-get update #   sudo apt-get install -y php5 sudo apt-get install -y apache2 sudo apt-get install -y libapache2-mod-php5 sudo apt-get install -y mysql-server sudo apt-get install -y php5-mysql sudo apt-get install -y php5-curl sudo apt-get install -y php5-gd sudo apt-get install -y php5-mcrypt sudo apt-get install -y git-core sudo apt-get install -y phpmyadmin #   phpmyadmin echo "Include /etc/phpmyadmin/apache.conf" | sudo tee -a /etc/apache2/apache2.conf #  mod_rewrite sudo a2enmod rewrite #  apache    sudo /etc/init.d/apache2 restart #   Composer curl -sS https://getcomposer.org/installer | php sudo mv composer.phar /usr/local/bin/composer 

рдереЛрдбрд╝реА рджреЗрд░ рдмрд╛рдж, рдЖрдкрдХреЗ рдкрд╛рд╕ рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рдЙрдкрдХрд░рдг рд╕реНрдерд╛рдкрд┐рдд рд╣реЛрдВрдЧреЗред
рд╣рдо рд╕реАрдзреЗ Laravel рдХреА рд╕реНрдерд╛рдкрдирд╛ рдХреЗ рд▓рд┐рдП рдЖрдЧреЗ рдмрдврд╝рддреЗ рд╣реИрдВред

 #     cd #    /home/%user% mkdir workspace #  workspace cd workspace #    mkdir php #   php cd php #    php 

рд╣реИрдмреНрд░ рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рд▓рд╛рд░реНрд╡рд╛ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдмрдирд╛рдПрдВ

 composer create-project laravel/laravel habr --prefer-dist # ....       .... 

рдЖрдЗрдП, рдмрдирд╛рдИ рдЧрдИ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдкрд░ рдЬрд╛рдПрдВ рдФрд░ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдХрд┐ php artisan serve рдХрдорд╛рдВрдб рдЪрд▓рд╛рдХрд░ рд╕рдм рдХреБрдЫ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ

 cd habr php artisan serve 

рд╕реНрдерд╛рдиреАрдп рд╕рд░реНрд╡рд░ http: // localhost: 8000 рдкрд░ рдЙрдкрд▓рдмреНрдз рд╣реЛрдЧрд╛ред

рдмрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдХрд╛рд░реАрдЧрд░ рдПрдХ рдХрдорд╛рдВрдб-рд▓рд╛рдЗрди рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╣реИ рдЬреЛ Laravel ред рдпрд╣ рд╡рд┐рдХрд╛рд╕ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХреЗ рд▓рд┐рдП рдХрдИ рдЙрдкрдпреЛрдЧреА рдХрдорд╛рдВрдб рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдпрд╣ Symfony рдХрдВрд╕реЛрд▓ рдШрдЯрдХ рдХреЗ рд╢реАрд░реНрд╖ рдкрд░ рдЪрд▓рддрд╛ рд╣реИред ( рдХрд╛рд░реАрдЧрд░ рд╕реАрдПрд▓рдЖрдИ )ред рдХрдИ рдЙрдкрдпреЛрдЧреА рдХрдорд╛рдВрдб рд╣реИрдВ рдЬрд┐рдирдХреЗ рд╕рд╛рде рдЖрдк рдХрдорд╛рдВрдб рд▓рд╛рдЗрди рдкрд░ рд╡рд┐рднрд┐рдиреНрди рдЙрдкрдпреЛрдЧреА рдЪреАрдЬреЗрдВ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред рдЖрджреЗрд╢реЛрдВ рдХреА рд╕реВрдЪреА рдХреЗ php artisan list , рдХрдорд╛рдВрдб рд▓рд╛рдЗрди рдкрд░ php artisan list рджрд░реНрдЬ рдХрд░реЗрдВред

рдкрддрд╛ : http: // localhost: 8000 рдкрд░ рдЬрд╛рдХрд░ рдЖрдкрдХреЛ рдкреЛрд╕реНрдЯ рдХреА рд╢реБрд░реБрдЖрдд рдореЗрдВ рдПрдХ рд╕реБрдВрджрд░ рд╕реНрдХреНрд░реАрди рд╕реЗрд╡рд░ рджреЗрдЦрдирд╛ рдЪрд╛рд╣рд┐рдПред

рд╕рдорд╛рдпреЛрдЬрди


рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдХрдиреЗрдХреНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП (рдмрд╛рдж рдореЗрдВ рдбреАрдмреА рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдВрджрд░реНрднрд┐рдд), Laravel рдкрд╛рд╕ рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди / рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рд╕реНрдерд┐рдд рдПрдХ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓ рдбреЗрдЯрд╛рдмреЗрд╕ рд╣реИ ред
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, MySQL рдореЗрдВ рдбреЗрдЯрд╛рдмреЗрд╕ рдФрд░ рдпреВрдЬрд░ рдмрдирд╛рдПрдВ

 mysql -u root -p #    > CREATE DATABASE `habr` CHARACTER SET utf8 COLLATE utf8_general_ci; > CREATE USER 'habr'@'localhost' IDENTIFIED BY 'my_password'; > GRANT ALL PRIVILEGES ON habr.* TO 'habr'@'localhost'; > exit 

рдмрд╣реБрдд рдмрдврд╝рд┐рдпрд╛! рд╣рдорд╛рд░реЗ рдкрд╛рд╕ MySQL рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рд╕рднреА рдбреЗрдЯрд╛ рд╣реИрдВ: рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ my_password рдХреЗ рд╕рд╛рде рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╣рдм рдФрд░ рд╕реНрдерд╛рдиреАрдп рд╣реЛрд╕реНрдЯ рдкрд░ рдбреЗрдЯрд╛рдмреЗрд╕ рд╣рдм ред рдЪрд▓реЛ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓ рдкрд░ рдЬрд╛рдПрдВ рдФрд░ рд╣рдорд╛рд░реА рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдмрджрд▓реЗрдВред

рд▓рд╛рд░рд╡реЗрд▓ DB рд╡рд┐рдиреНрдпрд╛рд╕ рдлрд╛рдЗрд▓

Laravel рдкрд╛рд╕ рдорд╣рд╛рди рдЙрдкрдХрд░рдг рд╣реИрдВ - рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдФрд░ рд╕реНрдХреАрдо рдмрд┐рд▓реНрдбрд░ ред
рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдПрдХ рдкреНрд░рдХрд╛рд░ рдХрд╛ рд╕рдВрд╕реНрдХрд░рдг рдирд┐рдпрдВрддреНрд░рдг рд╣реИред рд╡реЗ рд╡рд┐рдХрд╛рд╕ рдЯреАрдо рдХреЛ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реНрдХреАрдорд╛ рдХреЛ рдмрджрд▓рдиреЗ рдФрд░ рд╕реНрдХреАрдорд╛ рдХреА рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐ рдкрд░ рдЕрдкрдбреЗрдЯ рд░рд╣рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреЗ рд╣реИрдВред рдорд╛рдЗрдЧреНрд░реЗрд╢рди, рдПрдХ рдирд┐рдпрдо рдХреЗ рд░реВрдк рдореЗрдВ, рд╕реНрдХреАрдорд╛ рдмрд┐рд▓реНрдбрд░ рдХреЗ рд╕рд╛рде рдорд┐рд▓рдХрд░ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реНрдХреАрдорд╛ рдХрд╛ рдкреНрд░рдмрдВрдзрди рдХрд░рдирд╛ рдЖрд╕рд╛рди рд╣реЛрдЧрд╛ред
- рдкрд▓рд╛рдпрди
рд╕реНрдХреАрдорд╛ рдмрд┐рд▓реНрдбрд░ рд╕реНрдХреАрдорд╛ рд╡рд░реНрдЧ рд╣реИред рдпрд╣ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдореЗрдВ рд╣реЗрд░рдлреЗрд░ рдХрд░рдирд╛ рд╕рдВрднрд╡ рдмрдирд╛рддрд╛ рд╣реИред рдпрд╣ Laravel рджреНрд╡рд╛рд░рд╛ рд╕рдорд░реНрдерд┐рдд рд╕рднреА рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдЗрди рд╕рднреА рдкреНрд░рдгрд╛рд▓рд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдПрдХрд▓ API рд╣реИред
- рд╕реНрдХреАрдо рдмрд┐рд▓реНрдбрд░

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдПрдХ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдЯреЗрдмрд▓ рдмрдирд╛рдПрдВ:

 php artisan migrate:install 

рдпрджрд┐ рдбреЗрдЯрд╛рдмреЗрд╕ рдХрдиреЗрдХреНрд╢рди рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рд╕рд╣реА рд╣реИрдВ, рддреЛ рд╣рдо рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдФрд░ рдЯреЗрдмрд▓ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИрдВред
рд▓реЗрдХрд┐рди рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ, рдореИрдВ рдЖрдкрдХреЛ рдЕрддрд┐рд░рд┐рдХреНрдд рдкреИрдХреЗрдЬреЛрдВ рдХреА рд╕реНрдерд╛рдкрдирд╛ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рдХрд░рд╛рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдЬрд┐рдиреНрд╣реЗрдВ рдЕрдзрд┐рдХ рдХреБрд╢рд▓рддрд╛ рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдЬрд▓реНрджреА рд╕реЗ рдПрдХ рд╡реЗрдм рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред

рд▓рд╛рд░рд╛рд╡реЗрд▓ 4 рдЬреЗрдирд░реЗрдЯрд░

рдореЗрдЧрд╛ рдЙрдкрдпреЛрдЧреА рдЙрдкрдХрд░рдг - рдЬреЗрдлрд░реА рд╡реЗ рд╕реЗ рдЬрдирд░реЗрдЯрд░ ред GitHub ред

рдпрд╣ рдХрд╛рд░реАрдЧрд░ рд╕реВрдЪреА рдореЗрдВ рдХрдИ рдЙрдкрдпреЛрдЧреА рдХрдорд╛рдВрдб рдЬреЛрдбрд╝рддрд╛ рд╣реИ, рдЬреИрд╕реЗ:



рдкреИрдХреЗрдЬ рд╕реНрдерд╛рдкрдирд╛

Composer рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреИрдХреЗрдЬ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдирд╛ рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИред рдЖрдкрдХреЛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд░реВрдЯ рдореЗрдВ рдХрдВрдкреЛрдЬрд╝рд░.рдЬреЙрд╕рди рдлрд╝рд╛рдЗрд▓ рдХреЛ рд╕рдВрдкрд╛рджрд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛, "require" рдХреА рд╕реВрдЪреА рдореЗрдВ "require" "way/generators": "1.*" рдХреЛ рдЬреЛрдбрд╝рддреЗ рд╣реБрдПред

 "require": { "laravel/framework": "4.1.*", "way/generators": "1.*" }, 

рдЙрд╕рдХреЗ рдмрд╛рдж, рдЖрдкрдХреЛ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЯрд░реНрдорд┐рдирд▓ рдореЗрдВ рджрд░реНрдЬ рдХрд░реЗрдВ

 composer update 

рдЕрдВрддрд┐рдо рд╕реНрдкрд░реНрд╢ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдкреНрд░рджрд╛рддрд╛рдУрдВ рдХреА рд╕реВрдЪреА рдореЗрдВ рдПрдкреНрд▓рд┐рдХреЗрд╢рди / config / app.php рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рд╣реЛрдЧрд╛

 'Way\Generators\GeneratorsServiceProvider' 

рдЕрдм php artisan рдХрдорд╛рдВрдб рд▓рд┐рд╕реНрдЯ рдореЗрдВ рдирдП generate рдХрдорд╛рдВрдбреНрд╕ рднреА рд╣реЛрдВрдЧреЗред рдЕрдЧрд▓реЗ рднрд╛рдЧ рдореЗрдВ, рдореИрдВ рджрд┐рдЦрд╛рдКрдВрдЧрд╛ рдХрд┐ рдХреИрд╕реЗ рдПрдХ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рдиреЗ рдФрд░ рд╡рд┐рдХрд╛рд╕ рдХреЛ рдЧрддрд┐ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП generate рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдПред

рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдирд┐рд░реНрдорд╛рдг


рдорд╛рди рд▓реАрдЬрд┐рдП рд╣рдо рдЫреВрдЯ рдХреЗ рд╕рд╛рде рдПрдХ рдмреНрд▓реЙрдЧ рд╕рд╛рдЗрдЯ рдмрдирд╛рддреЗ рд╣реИрдВред рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдореЗрдВ рдЪрд╛рд╣рд┐рдП:



рд╣рдо рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдЯреЗрдмрд▓ рд╕реНрдХреАрдорд╛ рдХреА рд░реВрдкрд░реЗрдЦрд╛ рддреИрдпрд╛рд░ рдХрд░рддреЗ рд╣реИрдВред рдореБрдЭреЗ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рдорд┐рд▓рд╛:
рдкреВрд░реНрд╡ рдбреАрдмреА рд╕реНрдХреАрдорд╛

рдЗрд╕ рдЬрдирд░реЗрдЯрд░ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред рдЪреВрдБрдХрд┐ рдореИрдВрдиреЗ 10 рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд┐рдпрд╛ рдерд╛, рд╡реИрд╕реЗ рд╡реЗ рдпрд╣рд╛рдБ рд╣реИрдВ:

 php artisan generate:migration create_users_table --fields="email:string:unique, password:string[60], username:string:unique, remember_token:string:nullable" php artisan generate:scaffold role --fields="role:string:unique" php artisan generate:pivot users roles php artisan generate:scaffold city --fields="name:string:unique" php artisan generate:scaffold company --fields="title:string:unique" php artisan generate:scaffold tag --fields="title:string:unique" php artisan generate:scaffold offer --fields="title:string, description:text, city_id:integer:unsigned, company_id:integer:unsigned, off:integer:unsigned, image:string, expires:date" php artisan generate:scaffold comment --fields="body:text, user_id:integer:unsigned, offer_id:integer:unsigned, mark:integer" php artisan generate:pivot offers tags #      php artisan migrate 

рдЕрдВрддрд┐рдо рдЖрджреЗрд╢ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рд╕рднреА рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдЬреЛ рдЕрднреА рддрдХ рджрд░реНрдЬ рдирд╣реАрдВ рдХрд┐рдП рдЧрдП рд╣реИрдВ, рдЙрдиреНрд╣реЗрдВ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рджрд░реНрдЬ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдорд╣рддреНрд╡рдкреВрд░реНрдг рдмрд╛рдд рдпрд╣ рд╣реИ рдХрд┐ рд╕рднреА рдирдП рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдПрдХ рд╕реНрдЯреИрдХ рджреНрд╡рд╛рд░рд╛ рд▓реЙрдиреНрдЪ рдХрд┐рдП рдЬрд╛рдПрдВрдЧреЗред рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдХреЛ рд╡рд╛рдкрд╕ рд░реЛрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ php artisan migrate:rollback рдХрдорд╛рдВрдб, рдФрд░ рд╢реВрдиреНрдп migrate:reset рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рднреА рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдХреЛ рд░реЛрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП migrate:reset , рд╢реВрдиреНрдп рдкрд░ рд░реЛрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдФрд░ рд╕рднреА migrate:refresh рдЪрд▓рд╛рдиреЗ рдХреЗ migrate:refresh рдорд╛рдЗрдЧреНрд░реЗрд╢рдиред

рд▓рд╛рд░рд╡реЗрд▓ рд╕рдВрд╕реНрдХрд░рдг 4.1.25 рд╕реЗ рдЕрдзрд┐рдХ рдореЗрдВ , рдПрдХ рд╕реБрд░рдХреНрд╖рд╛ рдЕрджреНрдпрддрди рдерд╛ рдЬрд╣рд╛рдВ рдЙрдиреНрд╣реЛрдВрдиреЗ рдЪреБрд░рд╛рдП рдЧрдП рдХреБрдХреАрдЬрд╝ рдХреЗ рд╕рд╛рде рдПрдХ рдЫреЗрдж рдмрдВрдж рдХрд░ рджрд┐рдпрд╛ред рдЕрджреНрдпрддрди рдФрд░ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХрд╛ рд╡рд┐рд╡рд░рдг рдпрд╣рд╛рдВ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ: http://laravel.com/docs/upgrad рдЬрд┐рдирдХреЗ рдкрд╛рд╕ рд▓рд╛рд░рд╡реЗрд▓ < 4.1.26 рдХрд╛ рдПрдХ рд╕рдВрд╕реНрдХрд░рдг рд╣реИред рдпрд╛ рд╕рд┐рд░реНрдл vlom88 http://habrahabr.ru/post/197454/#comment_757479 рд╕реЗ рдЯрд┐рдкреНрдкрдгреА рдкрдврд╝реЗрдВред


рдЬрдирд░реЗрдЯрд░ рдЖрджреЗрд╢реЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА:



рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдЬрдирд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдпрд╣ рдЙрджрд╛рд╣рд░рдг рдХрд╛рдлреА рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рджрд┐рдЦрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд░реЗрдВ рдФрд░ рдпрд╣ рдХрд┐рддрдирд╛ рдЙрдкрдпреЛрдЧреА рд╣реИред

рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЕрднреА рднреА рдХрдореА рд╣реИ рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдХреЗ рдмреАрдЪ рдХреБрдЫ рд▓рд┐рдВрдХ рд╣реИрдВред
рдпрд╣ рдЬрд╛рдирдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ! рдХрд┐рд╕реА рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдПрдХ рд╕реНрддрдВрдн рдореЗрдВ рдПрдХ рд╡рд┐рджреЗрд╢реА рдХреБрдВрдЬреА рдЬреЛрдбрд╝рддреЗ рд╕рдордп, рдЖрдкрдХреЛ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ рдХрд┐ рд╕реНрддрдВрдн рдЕрд╣рд╕реНрддрд╛рдХреНрд╖рд░рд┐рдд рд╣реИред

рдЦреИрд░, рдЙрдиреНрд╣реЗрдВ рдЬреЛрдбрд╝реЗрдВ:

 php artisan generate:migration add_foreign_user_id_and_offer_id_to_comments_table php artisan generate:migration add_foreign_city_id_and_company_id_to_offers_table 

рдЕрдм рд╣рдореЗрдВ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рдЕрдВрджрд░ рдЗрдВрдбреЗрдХреНрд╕ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕ рддрд░рд╣ рдХреЗ рдмрджрд▓рд╛рд╡ рд╕реНрд╡рддрдГ рдирд╣реАрдВ рд╣реЛрддреЗ рд╣реИрдВред

 ... class AddForeignUserIdAndOfferIdToCommentsTable extends Migration { ... public function up() { Schema::table('comments', function(Blueprint $table) { $table->index('user_id'); $table->index('offer_id'); $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); $table->foreign('offer_id')->references('id')->on('offers')->onDelete('cascade'); }); } ... public function down() { Schema::table('comments', function(Blueprint $table) { $table->dropForeign('comments_user_id_foreign'); $table->dropForeign('comments_offer_id_foreign'); $table->dropIndex('comments_user_id_index'); $table->dropIndex('comments_offer_id_index'); }); } } ... class AddForeignCityIdAndCompanyIdToOffersTable extends Migration { ... public function up() { Schema::table('offers', function(Blueprint $table) { $table->index('city_id'); $table->index('company_id'); $table->foreign('city_id')->references('id')->on('cities')->onDelete('cascade'); $table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade'); }); } ... public function down() { Schema::table('offers', function(Blueprint $table) { $table->dropForeign('offers_city_id_foreign'); $table->dropForeign('offers_company_id_foreign'); $table->dropIndex('offers_city_id_index'); $table->dropIndex('offers_company_id_index'); }); } } 

рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реНрдХреАрдорд╛ рдХреЛ рджреЗрдЦрддреЗ рд╣реБрдП, рд╣рдо рдПрдХ рдмреЗрд╣рддрд░ рд╕реНрдерд┐рддрд┐ рджреЗрдЦрддреЗ рд╣реИрдВ
рдХреВрд▓ рдбреАрдмреА рд╕реНрдХреАрдорд╛

рдлрд┐рд▓рд╣рд╛рд▓, рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЗ рд╕рднреА рд▓рд┐рдВрдХ рдЦреБрд▓реЗ рд╣реИрдВ, рдФрд░ рдЙрдиреНрд╣реЗрдВ рдХрд┐рд╕реА рдХреЛ рднреА рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рд╣рдо рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рднреВрдорд┐рдХрд╛ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВред Http: // localhost: 8000 / рднреВрдорд┐рдХрд╛рдУрдВ рдХреЗ рд▓рд┐рдВрдХ рдкрд░ , рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЪрд┐рддреНрд░ рджреЗрдЦрддреЗ рд╣реИрдВ:
рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдХреА рднреВрдорд┐рдХрд╛ рдЬреЛрдбрд╝реА рдЧрдИ

Laravel рдореЗрдВ рдЯреЗрдореНрдкрд▓реЗрдЯ рдФрд░ рдмреНрд▓реЗрдб рдЯреЗрдореНрдкрд▓реЗрдЯ рдЗрдВрдЬрди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдереЛрдбрд╝рд╛ рд╕рд╛ред
рдЯреЗрдореНрдкрд▓реЗрдЯ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рд▓рд┐рдП, рдПрдХреНрд╕рдЯреЗрдВрд╢рди .blade.php рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ ред рдлрд╝рд╛рдЗрд▓ рдРрдк / рд╡рд┐рдЪрд╛рд░ / рд▓реЗрдЖрдЙрдЯ / scaffold.blade.php рдХреЛ рджреЗрдЦрддреЗ рд╣реБрдП рд╣рдо рджреЗрдЦрддреЗ рд╣реИрдВ

 // app/views/layouts/scaffold.blade.php <!doctype html> <html> <head> <meta charset="utf-8"> <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet"> <style> table form { margin-bottom: 0; } form ul { margin-left: 0; list-style: none; } .error { color: red; font-style: italic; } body { padding-top: 20px; } </style> </head> <body> <div class="container"> @if (Session::has('message')) <div class="flash alert"> <p>{{ Session::get('message') }}</p> </div> @endif @yield('main') </div> </body> </html> 

рдпрд╣рд╛рдВ рдХреНрдпрд╛ рд╣реЛ рд░рд╣рд╛ рд╣реИ? рдлрд╝рд╛рдЗрд▓ рдЕрдкрдиреЗ рдЖрдк рдореЗрдВ рдПрдХ рдХрдВрдХрд╛рд▓ рд╣реИ, рдПрдХ рд▓реЗрдЖрдЙрдЯ рдЬрд┐рд╕реЗ main рдЕрдиреБрднрд╛рдЧ рдореЗрдВ рдХреБрдЫ рд╕рд╛рдордЧреНрд░реА рдпрд╛ рдХрд┐рд╕реА рдЕрдиреНрдп рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЛ рдЬреЛрдбрд╝рдХрд░ рд╡рд┐рд╕реНрддрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдбрдмрд▓ рдмреНрд░реЗрд╕реЗрд╕ {{$ var}} рдХреЗ рдЕрдиреБрд░реВрдк рд╣реИрдВ ; php рдЗрдХреЛ $ var; ?> ред рдпрджрд┐ рд╣рдо рдХрд┐рд╕реА рдкреНрд░рдХрд╛рд░ рдХрд╛ рд╕рдВрджреЗрд╢ рджреЗрддреЗ рд╣реИрдВ, рддреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рд╕рдВрджреЗрд╢ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рддреНрд░ рд╡рд░реНрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдпрд╣рд╛рдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╕рдВрджреЗрд╢ рдЕрд╕реНрдерд╛рдпреА рд╣реИ рдФрд░ рдкреЗрдЬ рддрд╛рдЬрд╝рд╛ рд╣реЛрдиреЗ рдкрд░ рдЧрд╛рдпрдм рд╣реЛ рдЬрд╛рдПрдЧрд╛ред рдпрджрд┐ рд╣рдо рдирдП рдмрдирд╛рдП рдЧрдП рдЯреЗрдореНрдкрд▓реЗрдЯ рдРрдк / рд╡рд┐рдЪрд╛рд░ / рднреВрдорд┐рдХрд╛ / index.blade.php рдЦреЛрд▓реЗрдВ

 // app/views/roles/index.blade.php @extends('layouts.scaffold') @section('main') <h1>All Roles</h1> <p>{{ link_to_route('roles.create', 'Add new role') }}</p> @if ($roles->count()) <table class="table table-striped table-bordered"> <thead> <tr> <th>Role</th> </tr> </thead> <tbody> @foreach ($roles as $role) <tr> <td>{{{ $role->role }}}</td> <td>{{ link_to_route('roles.edit', 'Edit', array($role->id), array('class' => 'btn btn-info')) }}</td> <td> {{ Form::open(array('method' => 'DELETE', 'route' => array('roles.destroy', $role->id))) }} {{ Form::submit('Delete', array('class' => 'btn btn-danger')) }} {{ Form::close() }} </td> </tr> @endforeach </tbody> </table> @else There are no roles @endif @stop 

рдпрд╣ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рд╕реНрдкрд╖реНрдЯ рд╣реЛ рдЬрд╛рдПрдЧрд╛ рдХрд┐ рдпрд╣ рдЯреЗрдореНрдкрд▓реЗрдЯ рдРрдк / рд╡рд┐рдЪрд╛рд░ / рд▓реЗрдЖрдЙрдЯ / scaffold.blade.php рдЯреЗрдореНрдкрд▓реЗрдЯ, @extends('layouts.scaffold') рдХреЛрдб рдЗрд╕рдХреЗ рд▓рд┐рдП рдмреЛрд▓рддрд╛ рд╣реИред рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдпрд╣рд╛рдБ рдПрдХ рдбреЙрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдлрд╝реЛрд▓реНрдбрд░реЛрдВ рдХреЛ рдЕрд▓рдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд╣рд╛рд▓рд╛рдБрдХрд┐ / рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рднреА рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рддрдм @stop рдХреА рдкрд╣рд▓реА рдЙрдкрд╕реНрдерд┐рддрд┐ рддрдХ рд╕рдм рдХреБрдЫ main рдЕрдиреБрднрд╛рдЧ рдХреЛ рд▓рд┐рдЦрд╛ рдЬрд╛рдПрдЧрд╛ред рдпрд╣ рдкрд░рд┐рдЪрд┐рдд рдХрд╛ рднреА рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ if - else - endif foreach - endforeach рдФрд░ foreach - endforeach , рд╣реЗрд▓реНрдкрд░ рдлрдВрдХреНрд╢рди foreach - endforeach , рдЬрд┐рд╕реЗ foreach - endforeach (рд╣реЗрд▓реНрдкрд░ рдлрдВрдХреНрд╢рдВрд╕) рдФрд░ Form рдХреНрд▓рд╛рд╕ рд╣рдореЗрдВ Form рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рджрд╛рди рдХрд░рддреЗ рд╣реИрдВ (рдЕрдзрд┐рдорд╛рдирддрдГ рдЖрдкрдХреЛ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдХрдо рд╕реЗ рдХрдо рдлреЙрд░реНрдо :: рдУрдкрди ::) рдпрд╣ рдХреИрд╕реЗ рдлреЙрд░реНрдо рдХрд╛ рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рдЧреБрдг рдмрдирд╛рддрд╛ рд╣реИ _token - PUT / PATCH рдпрд╛ DELETE рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдХреНрд░реЙрд╕- рд╕рд╛рдЗрдЯ рдЕрдиреБрд░реЛрдз рдЬрд╛рд▓рд╕рд╛рдЬреА рдФрд░ _method рдХреЗ рдЦрд┐рд▓рд╛рдл рд╕реБрд░рдХреНрд╖рд╛)ред

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдЖрдЗрдП рд╕рднреА рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреА рд╕реБрд░рдХреНрд╖рд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реЛрдЪреЗрдВред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

рдРрдк / рдХрдВрдЯреНрд░реЛрд▓рд░ рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рдПрдХ рдирдпрд╛ LoginContoller рдмрдирд╛рдПрдВ

 php artisan generate:controller LoginController 

рдФрд░ рдЗрд╕рдХреЗ рд▓рд┐рдП рдХреБрдЫ рдЯреЗрдореНрдкрд▓реЗрдЯ рдЬреЛрдбрд╝реЗрдВ

 mkdir app/views/login php artisan generate:view index --path="app/views/login" php artisan generate:view register --path="app/views/login" php artisan generate:view dashboard --path="app/views/login" 

рдЕрдм рдХрдВрдЯреНрд░реЛрд▓рд░ рдХреЛ рд╣реА рдмрджрд▓рддреЗ рд╣реИрдВред рд╣рдореЗрдВ 5 рд╡рд┐рдзрд┐рдпрд╛рдБ рдЪрд╛рд╣рд┐рдП:

рд╕рдВрд╢реЛрдзрд┐рдд LoginController рдЗрд╕ рддрд░рд╣ рджрд┐рдЦреЗрдЧрд╛:

 // app/controllers/LoginController.php class LoginController extends BaseController { /** * Login Form. * * @return Response */ public function index() { return View::make('login.index'); } /** * Registration form. * * @return Response */ public function register() { return View::make('login.register'); } /** * Registring new user and storing him to DB. * * @return Response */ public function store() { $rules = array( 'email' => 'required|email|unique:users,email', 'password' => 'required|alpha_num|between:4,50', 'username' => 'required|alpha_num|between:2,20|unique:users,username' ); $validator = Validator::make(Input::all(), $rules); if($validator->fails()){ return Redirect::back()->withInput()->withErrors($validator); } $user = new User; $user->email = Input::get('email'); $user->username = Input::get('username'); $user->password = Hash::make(Input::get('password')); $user->save(); Auth::loginUsingId($user->id); return Redirect::home()->with('message', 'Thank you for registration, now you can comment on offers!'); } /** * Log in to site. * * @return Response */ public function login() { if (Auth::attempt(array('email' => Input::get('email'), 'password' => Input::get('password')), true) || Auth::attempt(array('username' => Input::get('email'), 'password' => Input::get('password')), true)) { return Redirect::intended('dashboard'); } return Redirect::back()->withInput(Input::except('password'))->with('message', 'Wrong creadentials!'); } /** * Log out from site. * * @return Response */ public function logout() { Auth::logout(); return Redirect::home()->with('message', 'See you again!'); } } 

рдкрд╣рд▓реЗ рджреЛ рддрд░реАрдХреЗ HTML рдЯреЗрдореНрдкреНрд▓реЗрдЯ рд╕реЗ рдЙрддреНрдкрдиреНрди рд╣реЛрддреЗ рд╣реИрдВред
store рд╡рд┐рдзрд┐ рд╣рдорд╛рд░реЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд▓рд┐рдП рдПрдХ рдирдпрд╛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдмрдЪрд╛рддрд╛ рд╣реИ, рдкреАрдУрдЯреА рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЖрдиреЗ рд╡рд╛рд▓реЗ Input::all() рд╕реЗ рд╕рднреА рдбреЗрдЯрд╛ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИред ( рд╡рд┐рд╡рд░рдг )
Input рд╡рд░реНрдЧ рдореЗрдВ рд╡рд╣ рдбреЗрдЯрд╛ рд╣реЛрддрд╛ рд╣реИ рдЬреЛ POST рдЕрдиреБрд░реЛрдз рдХреЗ рджреМрд░рд╛рди рднреЗрдЬрд╛ рдЧрдпрд╛ рдерд╛ред рдЗрд╕рдХреА рдХрдИ рд╕реНрдерд┐рд░ рд╡рд┐рдзрд┐рдпрд╛рдБ рд╣реИрдВ, рдЬреИрд╕реЗ рдХрд┐ all() , get() , has() рдФрд░ рдЕрдиреНрдп ( рдмреЗрд╕рд┐рдХ рдЗрдирдкреБрдЯ )ред

Hash рдПрдХ рдПрдиреНрдХреНрд░рд┐рдкреНрд╢рди рдХреНрд▓рд╛рд╕ рд╣реИ рдЬреЛ bcrypt рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ рддрд╛рдХрд┐ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдкрд╛рд╕рд╡рд░реНрдб рдПрдХ рдПрдиреНрдХреНрд░рд┐рдкреНрдЯреЗрдб рд░реВрдк ( Laravel Security ) рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реЛрдВред

рд▓реЗрдХрд┐рди рдкрдВрдЬреАрдХрд░рдг рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рд╣рдореЗрдВ рдЖрдиреЗ рд╡рд╛рд▓реЗ рдбреЗрдЯрд╛ рдХреЛ рдорд╛рдиреНрдп рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред
рдЗрд╕рдХреЗ рд▓рд┐рдП, Laravel рдХрд╛ рдПрдХ рд╡реИрд▓рд┐рдбреЗрдЯрд░ рд╡рд░реНрдЧ рд╣реИред Validation::make рд╡рд┐рдзрд┐ 2 рдпрд╛ 3 рддрд░реНрдХ рд▓реЗрддреА рд╣реИ:
  1. $input - рдЖрд╡рд╢реНрдпрдХ, рдЗрдирдкреБрдЯ рдХреА рдПрдХ рд╕рд░рдгреА рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВ
  2. $rules - рдЖрд╡рд╢реНрдпрдХ, рдЖрдиреЗ рд╡рд╛рд▓реЗ рдбреЗрдЯрд╛ рдХреЗ рд▓рд┐рдП рдирд┐рдпрдореЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рд╕рд░рдгреА
  3. $messages - рд╡реИрдХрд▓реНрдкрд┐рдХ, рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢реЛрдВ рдХреЗ рд╕рд╛рде рд╕рд░рдгреА

рдЙрдкрд▓рдмреНрдз рдирд┐рдпрдореЛрдВ рдХреА рдкреВрд░реА рд╕реВрдЪреА рдпрд╣рд╛рдВ рдЙрдкрд▓рдмреНрдз рдорд╛рдиреНрдпрдХрд░рдг рдирд┐рдпрдореЛрдВ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХреА рдЬрд╛ рд╕рдХрддреА рд╣реИред

fails() рд╡рд┐рдзрд┐ рдЗрд╕ рдмрд╛рдд рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддреА рд╣реИ рдХрд┐ рдбреЗрдЯрд╛ рд╕рд╣реА рд╣реИ рдпрд╛ рдЧрд▓рдд рд╣реИ рдпрд╛ рдирд╣реАрдВ, рдпрд╣ рдЗрд╕ рдмрд╛рдд рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рд╣рдорд╛рд░реЗ рджреНрд╡рд╛рд░рд╛ рдмрдирд╛рдП рдЧрдП рдирд┐рдпрдореЛрдВ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдбреЗрдЯрд╛ рдорд╛рдиреНрдп рд╣реИ рдпрд╛ рдирд╣реАрдВред

рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рди рдХреЗ рд▓рд┐рдП рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рди рд╡рд░реНрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЙрдирдХреЗ рддрд░реАрдХреЗ:


Auth рд╡рд░реНрдЧ рдПрдХ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рд╡рд░реНрдЧ рд╣реИ, рдЗрд╕рдореЗрдВ рдХрдИ рд╡рд┐рдзрд┐рдпрд╛рдБ рд╣реИрдВ, рдЬрд┐рдирдореЗрдВ loginUsingId($id) , рдЬреЛ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рдорд╛рдгрд┐рдд рдХрд░рддрд╛ рд╣реИ ( рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ )ред рдкрдВрдЬреАрдХрд░рдг рдХреЗ рдмрд╛рдж рд╕реЗ рд╣рдо рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдЕрдзрд┐рдХреГрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рд╣рдо рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред

рд╣рдорд╛рд░реЗ рдирд┐рдпрдВрддреНрд░рдХ login() рдХреА рд╡рд┐рдзрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ email рдпрд╛ username рдЕрдзрд┐рдХреГрдд рдХрд░рддреА рд╣реИ рдФрд░ рдЙрд╕ рдкреГрд╖реНрда рдкрд░ рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рд┐рдд рдХрд░рддреА рд╣реИ, рдЬрд╣рд╛рдВ рд╕реЗ рд╡рд╣ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдлрд╝рд┐рд▓реНрдЯрд░ рдХреЗ рддрд╣рдд рдЖрдпрд╛ рдерд╛ред рдбреЗрдЯрд╛ рдорд┐рд╕рдореИрдЪ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЖрдиреЗ рд╡рд╛рд▓реЗ рдбреЗрдЯрд╛, рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢ рдХреЗ рд╕рд╛рде рд╡рд╛рдкрд╕ рднреЗрдЬ рджреЗрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдкрд╛рд╕рд╡рд░реНрдб рдХреЗ рдмрд┐рдирд╛ред

рдЗрд╕рд▓рд┐рдП рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдирд┐рдпрдВрддреНрд░рдХ рд╣реИ рдЬреЛ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИред

рдПрдХреНрд╕реЗрд╕ рд╕реЗ рд╕рднреА рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЛ рдЫрд┐рдкрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдЧрд▓рд╛ рдХрджрдо рдРрдк / рдорд╛рд░реНрдЧреЛрдВ рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдлрд╝рд╛рдЗрд▓ , рдЬрд┐рд╕рдореЗрдВ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдорд╛рд░реНрдЧ рд╢рд╛рдорд┐рд▓ рд╣реИрдВред

 // app/routes.php ... Route::get('/', array('as' => 'home', function() { return View::make('hello'); })); Route::get('logout', array('as' => 'login.logout', 'uses' => 'LoginController@logout')); Route::group(array('before' => 'un_auth'), function() { Route::get('login', array('as' => 'login.index', 'uses' => 'LoginController@index')); Route::get('register', array('as' => 'login.register', 'uses' => 'LoginController@register')); Route::post('login', array('uses' => 'LoginController@login')); Route::post('register', array('uses' => 'LoginController@store')); }); Route::group(array('before' => 'admin.auth'), function() { Route::get('dashboard', function() { return View::make('login.dashboard'); }); Route::resource('roles', 'RolesController'); Route::resource('cities', 'CitiesController'); Route::resource('companies', 'CompaniesController'); Route::resource('tags', 'TagsController'); Route::resource('offers', 'OffersController'); Route::resource('comments', 'CommentsController'); }); Route::filter('admin.auth', function() { if (Auth::guest()) { return Redirect::to('login'); } }); Route::filter('un_auth', function() { if (!Auth::guest()) { Auth::logout(); } }); 

рдЕрдм рд▓рд┐рдВрдХ рдХреЗ рдмрд╛рдж, рдЙрджрд╛рд╣рд░рдг / рднреВрдорд┐рдХрд╛рдУрдВ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ / рд▓реЙрдЧрд┐рди рдкреГрд╖реНрда рдкрд░ рдкреБрдирдГ рдирд┐рд░реНрджреЗрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдЬреЛ рдЕрдм рддрдХ рдХреЗрд╡рд▓ рдорд╛рдирдХ рдкрд╛рда "index.blade.php" рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИред

рд░реВрдЯ рдореЗрдВ рд╕рдВрд▓рдЧреНрди рд╕рднреА рдорд╛рд░реНрдЧреЛрдВ рдХреЗ рд▓рд┐рдП Route::group(array('before' => 'admin.auth')) , admin.auth рдлрд╝рд┐рд▓реНрдЯрд░ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдЬреЛ рдпрд╣ рдЬрд╛рдВрдЪрддрд╛ рд╣реИ рдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрддрд┐рдерд┐ рд╣реИ рдпрд╛ рдирд╣реАрдВ, рдФрд░ рдпрджрд┐ - рдЗрд╕реЗ рд▓реЙрдЧрд┐рди рдкреГрд╖реНрда рдкрд░ рднреЗрдЬреЗрдЧрд╛ред рдЖрдк рдпрд╣рд╛рдВ рдлрд┐рд▓реНрдЯрд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ, рдФрд░ рдпрд╣рд╛рдВ рдЧреНрд░реБрдкрд┐рдВрдЧ рд░реВрдЯ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВред рдПрдХ рдЕрдиреНрдп рдлрд╝рд┐рд▓реНрдЯрд░ Route::group(array('before' => 'un_auth')) рдпрд╣ рдЬрд╛рдБрдЪ рдХрд░реЗрдЧрд╛ рдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╕рд╛рдЗрдЯ рдкрд░ рд▓реЙрдЧ рдСрди рд╣реИ рдпрд╛ рдирд╣реАрдВ, рдФрд░ рдпрджрд┐ рд╕рддреНрдпрд╛рдкрди рдкреВрд░рд╛ рд╣реЛ рдЧрдпрд╛ рд╣реИ, рддреЛ рд╡рд╣ рдЗрд╕реЗ рдмрдВрдж рдХрд░ рджреЗрддрд╛ рд╣реИред

рд╕рд╛рдорд╛рдиреНрдп рдСрдкрд░реЗрд╢рди рдХреЗ рд▓рд┐рдП, рд▓реЙрдЧрд┐рди рдФрд░ рдкрдВрдЬреАрдХрд░рдг рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдмрджрд▓реЗрдВ:

 // app/views/login/index.blade.php @extends('layouts.scaffold') @section('main') <h1>Login</h1> <p>{{ link_to_route('login.register', 'Register') }}</p> {{ Form::open(array('route' => 'login.index')) }} <ul> <li> {{ Form::label('email', 'Email or Username:') }} {{ Form::text('email') }} </li> <li> {{ Form::label('password', 'Password:') }} {{ Form::password('password') }} </li> <li> {{ Form::submit('Submit', array('class' => 'btn btn-info')) }} </li> </ul> {{ Form::close() }} @include('partials.errors', $errors) @stop // app/views/login/register.blade.php @extends('layouts.scaffold') @section('main') <h1>Register</h1> <p>{{ link_to_route('login.index', 'Login') }}</p> {{ Form::open(array('route' => 'login.register')) }} <ul> <li> {{ Form::label('email', 'Email:') }} {{ Form::text('email') }} </li> <li> {{ Form::label('username', 'Username:') }} {{ Form::text('username') }} </li> <li> {{ Form::label('password', 'Password:') }} {{ Form::password('password') }} </li> <li> {{ Form::submit('Submit', array('class' => 'btn btn-info')) }} </li> </ul> {{ Form::close() }} @include('partials.errors', $errors) @stop // app/views/login/dashboard.blade.php @extends('layouts.scaffold') @section('main') <h1>Administrative Dashboard</h1> <p>Nice to see you, <b>{{{ Auth::user()->username }}}</b></p> @stop // app/views/partials/errors.blade.php @if ($errors->any()) <ul> {{ implode('', $errors->all('<li class="error">:message</li>')) }} </ul> @endif 

рдЬреИрд╕рд╛ рдХрд┐ рдЖрдкрдиреЗ рджреЗрдЦрд╛, рдпрд╣рд╛рдБ рдореИрдВрдиреЗ рдЯреЗрдореНрдкрд▓реЗрдЯ рдЗрдВрдЬрди рдореЗрдВ рдПрдХ рдирдИ рдЪрд╛рд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рд╣реИ @include('view', $variable)ред рдЖрд╡реЗрджрди рдореЗрдВ, рдпрд╣ рдмрд╣реБрдд рд╕рд░рд▓ рд╣реИ - 2 рддрд░реНрдХ рдкрд╛рд╕ рдХрд░реЗрдВ:
  1. рджреГрд╢реНрдп - рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЯреЗрдореНрдкрд▓реЗрдЯ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдХрд┐рдпрд╛ рдЬрд╛рдиреЗ рд╡рд╛рд▓рд╛ рдЯреЗрдореНрдкрд▓реЗрдЯ
  2. $ рдЪрд░ - рд╡рд╣ рдЪрд░ рдЬрд┐рд╕реЗ рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЛ рд░реЗрдВрдбрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╛рд╕ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП

рд╕рд╛рдЗрдЯ рдкрд░ рдкрд╣реБрдВрдЪ рдХреЗ рд▓рд┐рдП рд╕рд╛рдЗрдЯ рдкрд░ рд░рдЬрд┐рд╕реНрдЯрд░ рдХрд░реЗрдВред

рдареАрдХ рд╣реИ, рдЕрдм рдЖрдк рд╕рдВрд╕рд╛рдзрди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╢реБрд░реБрдЖрдд рдХрд░рддреЗ рд╣реИрдВ рд╢рд╣рд░реЛрдВ рд╕реЗред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рдореЙрдбрд▓ рдореЗрдВ Cityрд╕рддреНрдпрд╛рдкрди рдирд┐рдпрдореЛрдВ рдХреЛ рдмрджрд▓ рджреЗрдВрдЧреЗ :

 // app/models/City.php class City extends Eloquent { protected $guarded = array(); public static $rules = array( 'name' => 'required|alpha|min:2|max:200|unique:cities,name' ); } 

рдЗрд╕рдХреЗ рдмрд╛рдж, рд╣рдо рдореЙрдбрд▓ рдХреЗ рд▓рд┐рдП рд╕рддреНрдпрд╛рдкрди рдирд┐рдпрдо рднреА рдмрджрд▓ рджреЗрдВрдЧреЗ Company, RoleрдФрд░ Tag:

 // app/models/Company.php ... public static $rules = array( 'name' => 'required|alpha|min:2|max:200|unique:companies,name' ); ... // app/models/Role.php ... public static $rules = array( 'role' => 'required|alpha|min:2|max:200|unique:roles,role' ); ... // app/models/Tag.php ... public static $rules = array( 'name' => 'required|min:2|max:200|unique:tags,name' ); ... 

рд▓рд┐рдВрдХ рдХреЗ рдмреАрдЪ рд╕реНрд╡рд┐рдЪ рдХрд░рдиреЗ рдХреА рд╕реБрд╡рд┐рдзрд╛ рдХреЗ рд▓рд┐рдП, рдРрдк / рд╡рд┐рдЪрд╛рд░ / рд▓реЗрдЖрдЙрдЯ / scaffold.blade.php рдореЗрдВ рдПрдХ рдореЗрдиреВ рдЬреЛрдбрд╝реЗрдВ , рдФрд░ рднрд╡рд┐рд╖реНрдп рдХреА рдЬрд░реВрд░рддреЛрдВ рдХреЗ рд▓рд┐рдП jQuery рдФрд░ jQuery-UI рднреА рдЬреЛрдбрд╝реЗрдВ

 // app/views/layouts/scaffold.blade.php <!doctype html> <html> <head> <meta charset="utf-8"> <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet"> <link href="//code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" rel="stylesheet"> <style> table form { margin-bottom: 0; } form ul { margin-left: 0; list-style: none; } .error { color: red; font-style: italic; } body { padding-top: 20px; } input, textarea, .uneditable-input {width: 50%; min-width: 200px;} </style> @yield('styles') </head> <body> <div class="container"> <ul class="nav nav-pills"> <li>{{ link_to_route('offers.index', 'Offers') }}</li> <li>{{ link_to_route('tags.index', 'Tags') }}</li> <li>{{ link_to_route('roles.index', 'Roles') }}</li> <li>{{ link_to_route('cities.index', 'Cities') }}</li> <li>{{ link_to_route('comments.index', 'Comments') }}</li> <li>{{ link_to_route('companies.index', 'Companies') }}</li> <li class="pull-right">{{ link_to_route('login.logout', 'Logout') }}</li> </ul> @if (Session::has('message')) <div class="flash alert"> <p>{{ Session::get('message') }}</p> </div> @endif @yield('main') </div> <script type="text/javascript" src="//code.jquery.com/jquery.min.js"></script> <script type="text/javascript" src="//code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script> @yield('scripts') </body> </html> 

рдЗрд╕рдХреЗ рдмрд╛рдж, рд╣рдо рдореЙрдбрд▓ рдореЗрдВ рд╕рддреНрдпрд╛рдкрди рдирд┐рдпрдореЛрдВ рдХреЛ рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВрдЧреЗ Offer:

 // app/models/Offer.php ... public static $rules = array( 'title' => 'required|between:5,200', 'description' => 'required|min:10', 'city_id' => 'required|exists:cities,id', 'company_id' => 'required|exists:companies,id', 'off' => 'required|numeric|min:1|max:100', 'image' => 'required|regex:/\/images\/\d{4}\/\d{2}\/\d{2}\/([A-z0-9]){30}\.jpg/', // matches /images/2012/12/21/ThisIsTheEndOfTheWorldMaya2112.jpg 'expires' => 'required|date' ); 

рдпрд╣рд╛рдВ рдореИрдВрдиреЗ рдлрд╝реАрд▓реНрдб рдХреЗ рд▓рд┐рдП рдПрдХ рдЬрдЯрд┐рд▓ рдкреИрдЯрд░реНрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рд╣реИ image, рдХреНрдпреЛрдВрдХрд┐ рдореИрдВ AJAXрдЪрд┐рддреНрд░реЛрдВ рдХреЛ рдЕрдкрд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд╕рд╛рдзрдиреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ , рдФрд░ рд╕рд░реНрд╡рд░ рдкрд░ рдХреЗрд╡рд▓ рдЪрд┐рддреНрд░ рдХрд╛ рдкрде рд╕рддреНрдпрд╛рдкрди рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рддреЛ рдЪрд▓рд┐рдП рдЯреЗрдореНрдкрд▓реЗрдЯ рдРрдк / рд╡рд┐рдЪрд╛рд░ / рдСрдлрд╝рд░ / create.blade.php рдХреЛ рдмрджрд▓рдХрд░ рдФрд░ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрд▓рдЧ рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдХрд░ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред

 // app/views/offers/create.blade.php ... {{ Form::label('file', 'Image:') }} {{ Form::file('file')}} <img src="" id="thumb" style="max-width:300px; max-height: 200px; display: block;"> {{ Form::hidden('image') }} <div class="error"></div> ... @section('scripts') @include('offers.scripts') @stop // app/views/offers/scripts.blade.php <script> $(document).ready(function(){ //     $('#expires').datepicker({dateFormat: "yy-mm-dd"}); var uploadInput = $('#file'), //    imageInput = $('[name="image"]'), //   URL  thumb = document.getElementById('thumb'), //   error = $('div.error'); //      uploadInput.on('change', function(){ //     FormData var data = new FormData(); //      data.append('file', uploadInput[0].files[0]); //    $.ajax({ //   URL    url: '/upload', //   type: 'POST', //     data: data, //     jQuery   processData: false, //     jQuery    contentType: false, //      dataType: 'json', //      success: function(result) { //     (    result) //      filelink if (result.filelink) { //   URL    thumb.setAttribute('src', result.filelink); //    input' imageInput.val(result.filelink); //   error.hide(); } else { //      error.text(result.message); error.show(); } }, // -    error: function (result) { //     error.text("Upload impossible"); error.show(); } }); }); }); </script> 

рдпрд╣рд╛рдБ рд╣рдо рджрдмрд╛рдХрд░ рдЫрд╡рд┐ рдЬреЛрдбрд╝ рджреЗрдЧрд╛ input[name="file"]рдФрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рдЗрд╕реЗ рднреЗрдЬрдиреЗ AJAXрдкрд░ URL/ рдЕрдкрд▓реЛрдбред рдЗрд╕ URL рдХреА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдбрд╛рдЙрдирд▓реЛрдб рдХреА рдЧрдИ рдЫрд╡рд┐ рдХрд╛ рд▓рд┐рдВрдХ рд╣реЛрдЧреАред рд╣рдо рдЗрд╕ рд▓рд┐рдВрдХ рдХреЛ # рдердореНрдм рдЗрдореЗрдЬ рдХреА src рд╡рд┐рд╢реЗрд╖рддрд╛ рдореЗрдВ рд╕рдореНрдорд┐рд▓рд┐рдд рдХрд░реЗрдВрдЧреЗ рдФрд░ рдЗрд╕реЗ рдЫрд┐рдкреЗ рд╣реБрдП рдЗрдирдкреБрдЯ рдореЗрдВ рд╕реЗрд╡ рдХрд░реЗрдВрдЧреЗ imageред рдЗрд╕рдХреЗ рдмрд╛рдж, рд╣рдо рдПрдХ рдлрд╝рд╛рдЗрд▓ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди / routes.php рдРрдб marshut upload:

 // app/routes.php ... Route::group(array('before' => 'admin.auth'), function(){ ... Route::resource('comments', 'CommentsController'); Route::post('upload', array('uses' => 'HomeController@uploadOfferImage')); } ... 

рдЦреИрд░, рд╣рдордиреЗ URL рдкрдВрдЬреАрдХреГрдд рдХрд┐рдпрд╛, рдпрд╣ рддрд░реНрдХ рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдирд╛ рд╣реБрдЖ рд╣реИ HomeControllerред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдлрд╝рд╛рдЗрд▓ рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рдирд┐рдпрдВрддреНрд░рдХреЛрдВ / HomeController.php рдореЗрдВ рд╡рд┐рдзрд┐ рдЬреЛрдбрд╝реЗрдВuploadOfferImage
рдиреНрдпреВрдирддрдо:
 // app/controllers/HomeController.php class HomeController extends BaseController { ... public function uploadOfferImage() { $rules = array('file' => 'mimes:jpeg,png'); $validator = Validator::make(Input::all(), $rules); if ($validator->fails()) { return Response::json(array('message' => $validator->messages()->first('file'))); } $dir = '/images'.date('/Y/m/d/'); do { $filename = str_random(30).'.jpg'; } while (File::exists(public_path().$dir.$filename)); Input::file('file')->move(public_path().$dir, $filename); return Response::json(array('filelink' => $dir.$filename)); } } 

рд╕рдм рдХреБрдЫ рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИ: рдирд┐рдпрдо, рд╕рддреНрдпрд╛рдкрди, рддреНрд░реБрдЯрд┐рдпрд╛рдВ, рдЙрддреНрддрд░ред рд╢реБрд░реБрдЖрдд рдХреЗ рд▓рд┐рдП рдмрдЪрд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдЙрд╕ рдлрд╝реЛрд▓реНрдбрд░ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВрдЧреЗ рдЬрд┐рд╕рдореЗрдВ рд╣рдо рдЗрд╕реЗ рд╕рд╣реЗрдЬреЗрдВрдЧреЗ - рдпрд╣ public_path () / рдЪрд┐рддреНрд░ / рдЪрд╛рд▓реВ рд╡рд░реНрд╖ / рдорд╣реАрдирд╛ / рджрд┐рдирд╛рдВрдХ / ( public_path()рдпрд╣ Laravelрд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдкрде рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд╣рд╛рдпрдХ рдХрд╛рд░реНрдп рд╣реИ ), рдлрд┐рд░ рдПрдХ рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдБ str_random(30)30 рд▓рдВрдмрд╛рдИ рдФрд░ рд╡рд┐рд╕реНрддрд╛рд░ jpgред рдЙрд╕рдХреЗ рдмрд╛рдж, рд╣рдо рдХреНрд▓рд╛рд╕ InputрдФрд░ рдЙрд╕рдХреЗ рддрд░реАрдХреЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ file('file')->move('destination_path', 'filename'), рдЬрд╣рд╛рдБ: 'рдлрд╛рдЗрд▓' рдЖрдиреЗ рд╡рд╛рд▓реА рдлрд╛рдЗрд▓ рд╣реИ, 'рдбреЗрд╕реНрдЯрд┐рдиреЗрд╢рди_рдкрде' рд╡рд╣ рдлреЛрд▓реНрдбрд░ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рд╣рдо рдлрд╛рдЗрд▓ рдХреЛ рдЖрдЧреЗ рдмрдврд╝рд╛рддреЗ рд╣реИрдВ, рдлрд╛рдЗрд▓ рдХреЛ рд╕реЗрд╡ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП 'рдлрд╛рдЗрд▓рдирд╛рдо' рдирд╛рдо рд╣реИред
Response::jsonрдПрдХ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдЬрд╡рд╛рдм рджреЗрдВрдЧреЗ jsonред
рдмрд╣реБрдд рдмрдврд╝рд┐рдпрд╛!рдЕрдм рдлрд╛рдЗрд▓реЗрдВ рд▓реЛрдб рд╣реЛ рдЧрдИ рд╣реИрдВ AJAXред
AJAX рдиреЗ Laravel рдЕрдкрд▓реЛрдб рдХрд┐рдпрд╛ рд╣реИ
рдЕрдЧрд▓реЗ рдХрджрдо рдореЗрдВ рдмрджрд▓рд╛рд╡ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ Form::input('number', 'city_id'), рдФрд░ Form::input('number', 'company_id')рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде Selecta рдкрд░ред

 // app/views/offers/create.blade.php ... <?php $cities = array(0 => 'Choose city'); foreach (City::get(array('id', 'name')) as $city) { $cities[$city->id] = $city->name; } ?> <li> {{ Form::label('city_id', 'City_id:') }} {{ Form::select('city_id', $cities) }} </li> <?php $companies = array(0 => 'Choose company'); foreach (Company::get(array('id', 'name')) as $company) { $companies[$company->id] = $company->name; } ?> <li> {{ Form::label('company_id', 'Company_id:') }} {{ Form::select('company_id', $companies) }} </li> ... 

рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЖрдк рдпрд╣рд╛рдБ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдлреЙрд░реНрдо рдФрд░ рдПрдЪрдЯреАрдПрдордПрд▓ (рдбреНрд░реЙрдкрдбрд╛рдЙрди рд╕реВрдЪреА) ред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдо рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдореМрдЬреВрджрд╛ рд╢рд╣рд░реЛрдВ рдФрд░ рдХрдВрдкрдирд┐рдпреЛрдВ рд╕реЗ рдЪреБрдирдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реИрдВред

рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЕрднреА рднреА рдЬреЛ рдХрдореА рд╣реИ, рд╡рд╣ рд╣реИ рдбрд┐рд╕реНрдХрд╛рдЙрдВрдЯ рдореЗрдВ рдЯреИрдЧ рдЬреЛрдбрд╝рдирд╛ред рдпрд╣рд╛рдБ рд╕реНрд╡рдд: рдкреВрд░реНрдг рдХреЗ рд╕рд╛рде jquery-ui рд╣рдореЗрдВ рдХрдИ рдореВрд▓реНрдпреЛрдВ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдЧрд╛ ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рд╡рд┐рдЪрд╛рд░ / рдСрдлрд╝рд░ / create.blade.php рдХреЗ рд╕рд╛рде рдлрд╝рд╛рдЗрд▓ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░реЗрдВ :

 // app/views/offers/scripts.blade.php <script> $(document).ready(function(){ ... function split( val ) { return val.split( /,\s*/ ); } function extractLast( term ) { return split( term ).pop(); } $( "#tags" ) // don't navigate away from the field on tab when selecting an item .bind( "keydown", function( event ) { if ( event.keyCode === $.ui.keyCode.TAB && $( this ).data( "ui-autocomplete" ).menu.active ) { event.preventDefault(); } }) .autocomplete({ source: function( request, response ) { $.getJSON( "/tags", { term: extractLast( request.term ), }, function( data ) { response($.map(data, function(item) { return { value: item.name } })) } ); }, search: function() { // custom minLength var term = extractLast( this.value ); if ( term.length < 2 ) { return false; } }, focus: function() { // prevent value inserted on focus return false; }, select: function( event, ui ) { console.log(ui); console.log(this); var terms = split( this.value ); // remove the current input terms.pop(); // add the selected item terms.push( ui.item.value ); // add placeholder to get the comma-and-space at the end terms.push( "" ); this.value = terms.join( ", " ); return false; } }); }); </script> 

рдпрд╣ jqueryui.com рд╕реЗ рдПрдХ рдорд╛рдирдХ рдЙрдкрдпреЛрдЧ рдорд╛рдорд▓рд╛ рд╣реИ , рдХреЗрд╡рд▓ рд╕рд░реНрд╡рд░ рд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдмрд┐рдВрджреБ рдкрд░ рдереЛрдбрд╝рд╛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдкрддрд╛ рдЪрд▓рд╛ рдЬрд╛рддрд╛ рд╣реИ /tagsред рд╣рдо рдЗрд╕рдХреЗ рд▓рд┐рдП AJAXрдЕрдиреБрд░реЛрдз рдХреЗ рдЬрд╡рд╛рдм рдХреЗ рддрд░реНрдХ рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рддреЗ рд╣реИрдВ URLред

 // app/controllers/TagController.php class TagsController extends BaseController { ... /** * Display a listing of the resource. * * @return Response */ public function index() { $tags = $this->tag->all(); //   AJAX  if (Request::ajax()) { //    ,      $tags = Tag::where('name', 'like', '%'.Input::get('term', '').'%')->get(array('name')); //     json return $tags; } return View::make('tags.index', compact('tags')); } ... 

рджрд┐рд▓рдЪрд╕реНрдк рдмрд╛рдд рдпрд╣ рд╣реИ рдХрд┐ рдЕрдЧрд░ рд╣рдо рдЗрд╕реЗ рд╡рд╛рдкрд╕ рдХрд░ рджреЗрддреЗ рд╣реИрдВ рддреЛ рдпрд╣ EloquentрдПрдХ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдмрджрд▓ рдЬрд╛рддрд╛ рд╣реИ json, рдЗрд╕рд▓рд┐рдП рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдХреЛрдИ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ Response::json()ред рдФрд░ рдпрд╣рд╛рдБ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╕реНрд╡рддрдГ рдкреВрд░реНрдг рдЯреИрдЧ рд╣реИрдВред

рдЖрдЦрд┐рд░реА рдЪреАрдЬ рдЬреЛ рд╣рдореЗрдВ рдХрд░рдиреЗ рдХреА рдЬрд╝рд░реВрд░рдд рд╣реИ рд╡рд╣ рд╣реИ рдбрд┐рд╕реНрдХрд╛рдЙрдВрдЯ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рддрд░реНрдХ рдмрджрд▓рдирд╛ред
 // app/controllers/OffersController.php class OffersController extends BaseController { ... /** * Store a newly created resource in storage. * * @return Response */ public function store() { $rules = Offer::$rules; $rules['expires'] .= '|after:'.date('Ym-d', strtotime('+1 day')).'|before:'.date('Ym-d', strtotime('+1 month')); $validation = Validator::make(Input::all(), $rules); if ($validation->passes()) { $tags = array(); foreach (explode(', ', Input::get('tags')) as $tag_name) { if ($tag = Tag::where('name', '=', $tag_name)->first()) { $tags[] = $tag->id; } } if (count($tags) == 0) { return Redirect::route('offers.create') ->withInput() ->with('message', 'Insert at least one tag.'); } $offer = $this->offer->create(Input::except('tags', 'file')); $offer->tags()->sync($tags); return Redirect::route('offers.index'); } return Redirect::route('offers.create') ->withInput() ->withErrors($validation) ->with('message', 'There were validation errors.'); } ... 

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рдПрдХреНрд╕рдкрд╛рдпрд░ рдирд┐рдпрдо рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░реЗрдВрдЧреЗ рддрд╛рдХрд┐ рдЫреВрдЯ рдХрд▓ рд╕реЗ рдкрд╣рд▓реЗ рди рдЦрддреНрдо рд╣реЛ, рдФрд░ рдмрд╛рдж рдореЗрдВ 1 рдорд╣реАрдиреЗ рдмрд╛рдж рди рд╣реЛред рдЕрдЧрд▓рд╛, idрдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдЙрдирдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреА рдЬрд╛рдБрдЪ рдХрд░рддреЗ рд╣реБрдП, рдПрдХ рдЕрд▓рдЧ рд╕рд░рдгреА рдореЗрдВ рд╕рднреА рдЯреИрдЧ рдХрд╛ рдЪрдпрди рдХрд░реЗрдВ ред рдлрд┐рд░ рдпрд╣ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЫреЛрдЯрд╛ рд╕рд╛ рдЪреЗрдХ рдЖрддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдЯреИрдЧ рджрд░реНрдЬ рдХрд┐рдП рдЧрдП рд╣реИрдВред рдФрд░ рдмрд╣реБрдд рдЕрдВрдд рдореЗрдВ, рдПрдХ рдмрд╣реБрдд рд╣реА рджрд┐рд▓рдЪрд╕реНрдк рдЪрд╛рд▓: рдПрд▓реЛрдХреЗрдВрдЯ рдореЗрдВ, рдЖрдк рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рднрд┐рдиреНрди рд╕рдВрдмрдВрдзреЛрдВ ( рдПрд▓реЛрдХреЗрдВрдЯ рд░рд┐рд▓реЗрд╢рдирд╢рд┐рдк ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ , рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдСрдлрд╝рд░ рдореЙрдбрд▓ рдореЗрдВ рдХрдИ рдЯреИрдЧ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ, рд╣рдо рдЗрд╕реЗ рддрджрдиреБрд╕рд╛рд░ рдореЙрдбрд▓ рдореЗрдВ рд▓рд┐рдЦреЗрдВрдЧреЗред

 // app/models/Offer.php ... public function tags() { return $this->belongsToMany('Tag'); } ... 

рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдордиреЗ рдСрдлрд╝рд░ рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдПрдХ рд░рд┐рдХреЙрд░реНрдб рдФрд░ рдЯреИрдЧ рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдХрдИ рд░рд┐рдХреЙрд░реНрдб рдХреЗ рдмреАрдЪ рдПрдХ рд╕рдВрдмрдВрдз рдмрдирд╛рдпрд╛ ред рдЕрдм, рд╡рд┐рдзрд┐ рдХреА рдЪрд░реНрдЪрд╛ рдХрд░рддреЗ рд╣реБрдП, $offer->tags()рд╣рдо рдЙрди рд╕рднреА рдЯреИрдЧ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдХрд┐рд╕реА рд╡рд┐рд╢реЗрд╖ рдЫреВрдЯ рд╕реЗ рдЬреБрдбрд╝реЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдЗрд╕ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рд╣рдо рдЕрднреА рднреА рдордзреНрдпрд╡рд░реНрддреА рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рд╢реЗрд╖ рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ sync(array(1, 2, 3)), рдЬреЛ рдордзреНрдпрд╡рд░реНрддреА рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ offer_idрдЖрд╡рд╢реНрдпрдХ рд▓реЛрдЧреЛрдВ рдХреЛ рд▓рд┐рдЦреЗрдВрдЧреЗ tag_idред рдСрдлрд╝рд░_рдЯреИрдЧ рдЯреЗрдмрд▓ :
рдкрд┐рд╡рдЯ рдЯреЗрдмрд▓ рдЯреИрдЧ рдХрд░рдиреЗ рдХреА рдкреЗрд╢рдХрд╢ рдХрд░рддреЗ рд╣реИрдВ
рд╣рдореЗрдВ рдСрдлрд╝рд░ рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдФрд░ рд╢рд╣рд░реЛрдВ рдФрд░ рдХрдВрдкрдирд┐рдпреЛрдВ рдХреА рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдореЗрдВ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдХреЗ рдмреАрдЪ рд╕рдВрдмрдВрдз рдХреЛ рднреА рдЗрдВрдЧрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ :

 // app/models/Offer.php ... public function city() { return $this->belongsTo('City'); } public function company() { return $this->belongsTo('Company'); } public function tags() { return $this->belongsToMany('Tag'); } //         +     public function webDescription($options = array()) { $str = $this->description; if (isset($options['shorten'])) { $length = isset($options['length']) ? (int) $options['length'] : 250; $end = isset($options['end']) ? : 'тАж'; if (mb_strlen($str) > $length) { $str = mb_substr(trim($str), 0, $length); $str = mb_substr($str, 0, mb_strlen($str) - mb_strpos(strrev($str), ' ')); $str = trim($str.$end); } } $str = str_replace("\r\n", '<br>', e($str)); return $str; } } 

рдпрд╣ рдлрд╝рд╛рдЗрд▓ рдРрдк / рд╡рд┐рдЪрд╛рд░ / рдСрдлрд╝рд░ / index.blade.php рдХреЛ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИ

 // app/views/offers/index.blade.php @if ($offers->count()) <table class="table table-striped table-bordered"> <thead> <tr> <th>Title</th> <th>Description</th> <th>City</th> <th>Company</th> <th>Off</th> <th>Image</th> <th>Tags</th> <th>Expires</th> </tr> </thead> <tbody> @foreach ($offers as $offer) <tr> <td>{{{ $offer->title }}}</td> <td>{{ $offer->webDescription(array('shorten' => true, 'length' => 60)) }}</td> <td>{{{ $offer->city->name }}}</td> <td>{{{ $offer->company->name }}}</td> <td>{{{ $offer->off }}}</td> <td><img src="" style="max-width: 200px; max-height:150px;"></td> <td> @foreach($offer->tags as $tag) <span class="badge">{{{$tag->name}}}</span> @endforeach </td> <td>{{{ $offer->expires }}}</td> <td> {{ link_to_route('offers.edit', 'Edit', array($offer->id), array('class' => 'btn btn-info')) }} </td> <td> {{ Form::open(array('method' => 'DELETE', 'route' => array('offers.destroy', $offer->id))) }} {{ Form::submit('Delete', array('class' => 'btn btn-danger')) }} {{ Form::close() }} </td> </tr> @endforeach </tbody> </table> @else There are no offers @endif 

рдФрд░ рд╣рдо рдПрдХ рдорд╣рд╛рди рддрд╕реНрд╡реАрд░ рджреЗрдЦрддреЗ рд╣реИрдВ рдЬреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЫреВрдЯ рдХреА рд╕рдВрд░рдЪрдирд╛ рдХреЛ рджрд░реНрд╢рд╛рддрд╛ рд╣реИ:
рд╕рднреА рдСрдлрд░
{{{$ рд╕реНрдЯреНрд░рд┐рдВрдЧ}}} рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ рдХреА рд╕рд╛рдордЧреНрд░реА рдХреЛ $: рд╕реНрдЯреНрд░рд┐рдВрдЧ , рдкреВрд░реНрд╡ рдирд┐рд╖реНрдХрд╛рд╕рд┐рдд рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ htmlentities, рдХрд┐ рдирд╣реАрдВ рд╕реБрд░рдХреНрд╖рд┐рдд рдзрд░реНрдорд╛рдиреНрддрд░рд┐рдд рдЕрдХреНрд╖рд░ рд╣реИрдВ рдЬреЛ XSS рдХреЗ рдЦрд┐рд▓рд╛рдл рд░рдХреНрд╖рд╛ рдХрд░рддрд╛ рд╣реИред рдПрдХ рдПрдирд╛рд▓реЙрдЧ <?php echo htmlentities($string); ?>рдпрд╛ рдПрдХ рд╕рд╣рд╛рдпрдХ рдХрд╛рд░реНрдп рд╣реИLaravel e($string)


рдЕрдм рдпрд╣ рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рд╡рд┐рдЪрд╛рд░ / рдСрдлрд╝рд░ / edit.blade.php , рдРрдк / рд╡рд┐рдЪрд╛рд░ / рдСрдлрд╝рд░ / show.blade.php рдФрд░ рдРрдк / рдХрдВрдЯреНрд░реЛрд▓рд░ / OfferController.phpupdate рдореЗрдВ рд╡рд┐рдзрд┐ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИ ред рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рд╡рд┐рдЪрд╛рд░реЛрдВ / edit.blade.php рдХреЗ рд▓рд┐рдП рдХреЛрдб


 // app/views/offers/edit.blade.php @extends('layouts.scaffold') @section('main') <h1>Edit Offer</h1> {{ Form::model($offer, array('method' => 'PATCH', 'route' => array('offers.update', $offer->id))) }} <ul> <li> {{ Form::label('title', 'Title:') }} {{ Form::text('title') }} </li> <li> {{ Form::label('description', 'Description:') }} {{ Form::textarea('description') }} </li> <?php $cities = array(0 => 'Choose city'); foreach (City::get(array('id', 'name')) as $city) { $cities[$city->id] = $city->name; } ?> <li> {{ Form::label('city_id', 'City_id:') }} {{ Form::select('city_id', $cities) }} </li> <?php $companies = array(0 => 'Choose company'); foreach (Company::get(array('id', 'name')) as $company) { $companies[$company->id] = $company->name; } ?> <li> {{ Form::label('company_id', 'Company_id:') }} {{ Form::select('company_id', $companies) }} </li> <li> {{ Form::label('off', 'Off:') }} {{ Form::input('number', 'off') }} </li> <li> {{ Form::label('file', 'Image:') }} {{ Form::file('file')}} <img src="" id="thumb" style="max-width:300px; max-height: 200px; display:block; "> {{ Form::hidden('image') }} <div class="error"></div> </li> <li> {{ Form::label('expires', 'Expires:') }} {{ Form::text('expires') }} </li> <li> {{ Form::label('tags', 'Tags:') }} {{ Form::text('tags', Input::old('tags', implode(', ', array_fetch($offer->tags()->get(array('name'))->toArray(), 'name')))) }} </li> <li> {{ Form::submit('Update', array('class' => 'btn btn-info')) }} {{ link_to_route('offers.show', 'Cancel', $offer->id, array('class' => 'btn')) }} </li> </ul> {{ Form::close() }} @if ($errors->any()) <ul> {{ implode('', $errors->all('<li class="error">:message</li>')) }} </ul> @endif @stop @section('scripts') @include('offers.scripts') @stop 

рдкрд░рд┐рд╡рд░реНрддрди рдмрд╣реБрдд рдХреБрдЫ рдРрдк / рд╡рд┐рдЪрд╛рд░реЛрдВ / рдСрдлрд╝рд░ / create.blade.php рдХреЗ рд╕рдорд╛рди рд╣реИрдВ , рдХреЗрд╡рд▓ рдФрд░ рдЗрд╕рдореЗрдВ рдереЛрдбрд╝рд╛ рдЕрдВрддрд░ рд╣реИ {{ Form::text('tags', ... }}ред рддрд╕реНрд╡реАрд░ рдХреЗ рд╕рд╛рде рд╕рдм рдХреБрдЫ рд╕реНрдкрд╖реНрдЯ рд╣реИ: рдпрджрд┐ рдХреЛрдИ рдкреБрд░рд╛рдирд╛ рдЗрдирдкреБрдЯ рд╣реИ, рддреЛ рд╣рдо рдЗрд╕реЗ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рдЕрдЧрд░ рдпрд╣ рдирд╣реАрдВ рд╣реИ, рддреЛ imageрд╣рдорд╛рд░реА рдЫреВрдЯ рдХреЗ рдореВрд▓реНрдп рд╕реЗ ред рдХреЗ рд░реВрдк рдореЗрдВ Form::text('tags', ... )рд╣рдо, рд╕рдм рд╕реЗ рдкрд╣рд▓реЗ, рд╡реЗ рд╕рднреА рдЯреИрдЧ, рдЬреЛ рдХрд┐рд╕реА рд╡рд┐рд╢реЗрд╖ рдЫреВрдЯ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд▓реЗ рд▓рд┐рдпрд╛ $offer->tags()рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗрд╡рд▓ рдХреНрд╖реЗрддреНрд░ рд╕реЗ рдФрд░ vynyali nameред рдлрд┐рд░ рд╣рдордиреЗ рдПрдХ-рдЖрдпрд╛рдореА рд╕рд░рдгреА рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП Laravel array_fetch рд╕реЗ рдПрдХ рд╕рд╣рд╛рдпрдХ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ , рдФрд░ рдЕрдВрдд рдореЗрдВ рд╣рдордиреЗ рдЗрд╕ рд╕рд░рдгреА рдХреЛ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╕реЗ рдЬреЛрдбрд╝рд╛, рдПрдХ рдЕрд▓реНрдкрд╡рд┐рд░рд╛рдо рдФрд░ рдЙрдирдХреЗ рдмреАрдЪ рдПрдХ рд╕реНрдерд╛рди рдбрд╛рд▓рд╛ред рдХрд░рдиреЗ рдХреЗ

рд▓рд┐рдП рд╡рд┐рдзрд┐ рдмрджрд▓реЗрдВ :updateOfferController

 // app/controllers/OfferController.php class OffersController extends BaseController { ... public function update($id) { $offer = $this->offer->findOrFail($id); $rules = Offer::$rules; $rules['expires'] .= '|after:'.date('Ym-d', strtotime('+1 day')).'|before:'.date('Ym-d', strtotime('+1 month')); $validation = Validator::make(Input::all(), $rules); if ($validation->passes()) { $tags = array(); foreach (explode(', ', Input::get('tags')) as $tag_name) { if ($tag = Tag::where('name', '=', $tag_name)->first()) { $tags[] = $tag->id; } } if (count($tags) == 0) { return Redirect::route('offers.create') ->withInput() ->withErrors($validation) ->with('message', 'Insert at least one tag.'); } $offer->update(Input::except('tags', 'file', '_method')); $offer->tags()->sync($tags); return Redirect::route('offers.show', $id); } return Redirect::route('offers.edit', $id) ->withInput() ->withErrors($validation) ->with('message', 'There were validation errors.'); } ... 

рдРрдб рдореЗрдердб рдХреЗ рд╕рд╛рде рдЕрдВрддрд░ рдиреНрдпреВрдирддрдо рд╣реИрдВред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, 404 рддреНрд░реБрдЯрд┐ рдХреЛ рдлреЗрдВрдХ рджреЗрдВ рдпрджрд┐ рдЧрд▓рдд рдПрдХ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ id, рдФрд░ рджреВрд╕рд░реА рдмрд╛рдд, рд╣рдо рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ update($id)ред рд╡рд╣ рд╕рдм рдмрджрд▓рд╛рд╡ рд╣реИред

рдЕрдЧрд▓рд╛, рдлрд╝рд╛рдЗрд▓ рдРрдк / рд╡рд┐рдЪрд╛рд░ / рдСрдлрд╝рд░ / рд╢реЛ.рдмреНрд▓реЗрдб.php рдмрджрд▓реЗрдВ :

 // app/views/offers/show.blade.php ... <thead> <tr> <th>Title</th> <th>Description</th> <th>City_id</th> <th>Company_id</th> <th>Off</th> <th>Image</th> <th>Tags</th> <th>Expires</th> </tr> </thead> <tbody> <tr> <td>{{{ $offer->title }}}</td> <td>{{ $offer->webDescription(array('shorten' => true, 'length' => 60)) }}</td> <td>{{{ $offer->city->name }}}</td> <td>{{{ $offer->company->name }}}</td> <td>{{{ $offer->off }}}</td> <td><img src="" style="max-width: 200px; max-height:150px;"/></td> <td> @foreach($offer->tags as $tag) <span class="badge">{{{ $tag->name }}}</span> @endforeach </td> <td>{{{ $offer->expires }}}</td> ... 

рдЕрдм, рдЫреВрдЯ рдХреЛ рдмрджрд▓рдиреЗ рдХреЗ рдмрд╛рдж, рд╣рдо рдЗрд╕рдХреА рд╕рдВрд░рдЪрдирд╛ рдХреЛ рдЫрд╡рд┐ рдФрд░ рд╕рднреА рд╕рдВрдмрдВрдзрдкрд░рдХ рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдЦреВрдмрд╕реВрд░рддреА рд╕реЗ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдВрдЧреЗред

рдореБрдЦ рдкреГрд╖реНрда

рдпрд╣ рдЕрдВрддрддрдГ рд╕рд╛рдЗрдЯ рдХрд╛ рдореБрдЦреНрдп рдкреГрд╖реНрда рдмрдирд╛рдиреЗ рдХрд╛ рд╕рдордп рд╣реИред

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдПрдХ рдирдпрд╛ рдмрдирд╛рдПрдБ layout:

 // app/views/layouts/main.blade.php <!doctype html> <html> <head> <meta charset="utf-8"> <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet"> <link rel="stylesheet" type="text/css" href="{{ asset('css/main.css') }}"> @yield('styles') </head> <body> <div class="navbar navbar-fixed-top"> <div class="navbar-inner"> <div class="container"> <a class="brand" href="{{ route('home') }}">Habr Offers</a> <ul class="nav"> <li><a href="{{ route('home') }}">Home</a></li> </ul> </div> </div> </div> <div class="container"> @if (Session::has('message')) <div class="flash alert"> <p>{{ Session::get('message') }}</p> </div> @endif @yield('main') </div> <script type="text/javascript" src="//code.jquery.com/jquery.min.js"></script> <script type="text/javascript" src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script> @yield('scripts') </body> </html> 

рдФрд░ рд╕реНрдЯрд╛рдЗрд▓рд╢реАрдЯ рднреА:

 // public/css/main.css /*        -     */ body {padding-top: 60px;} /*  ,      */ .no_decoration:hover, .no_decoration:focus {text-decoration: none;} /*           /  */ .thumbnail .image-container {width: 100%; max-height: 200px; overflow: hidden;} .thumbnail .image-container img {min-width: 100%; min-height: 100%;} .thumbnail h3 {height: 40px; overflow: hidden;} .thumbnail .description {height: 100px; overflow: hidden;} 

рдлрд┐рд░ рдореБрдЦреНрдп рдкреГрд╖реНрда рдХреЗ рдорд╛рд░реНрдЧ рдХреЛ рдлрд┐рд░ рд╕реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВ:

 // app/routes.php Route::get('/', array('as' => 'home', 'uses' => 'HomeController@index')); 

HomeControllerрд▓рд╛рдкрддрд╛ рд╡рд┐рдзрд┐ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ index:

 // app/controllers/HomeController.php ... /** * Display a listing of offers. * * @return Response */ public function index() { $offers = Offer::orderBy('created_at', 'desc')->get(); return View::make('home.index', compact('offers')); } ... 

рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рд╡рд┐рдЪрд╛рд░ / рд╣реЛрдо рдлрд╝реЛрд▓реНрдбрд░ рдмрдирд╛рдПрдВ рдФрд░ рд╡рд╣рд╛рдВ index.blade.php рдлрд╝рд╛рдЗрд▓ рдЬреЛрдбрд╝реЗрдВ , рдФрд░ рдРрдк / рд╡рд┐рдЪрд╛рд░ / рдСрдлрд╝рд░ рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ _preview.blade.php рдлрд╝рд╛рдЗрд▓ рднреА рдмрдирд╛рдПрдВ

 // app/views/home/index.blade.php @extends('layouts.main') @section('main') <h1>{{ $title }}</h1> @if ($offers->count()) @foreach ($offers as $key => $offer) @if($key % 3 == 0) <div class="row-fluid"> <ul class="thumbnails"> @endif <li class="span4"> <div class="thumbnail"> @include('offers._preview', $offer) </div> </li> @if($key % 3 == 2 || $key == count($offers) - 1) </ul> </div> @endif @endforeach @else There are no offers @endif @stop // app/views/offers/_preview.blade.php <div class="image-container"> <img src=""> </div> <div class="caption"> <h3>{{{ $offer->title }}}</h3> <hr> <p class="description">{{ $offer->webDescription() }}</p> <hr> <p><span class="label label-important">{{{ $offer->off }}} % off</span></p> <p>Location: {{{ $offer->city->name }}}</p> <p>Offer by: {{{ $offer->company->name }}}</p> <p>Expires on: <span class="label label-warning">{{{ $offer->expires }}}</span></p> <p>Tags: @foreach($offer->tags as $tag) <span class="badge">{{{$tag->name}}}</span> @endforeach </p> </div> 

рдЗрд╕рдХреЗ рдмрд╛рдж, рдЖрдкрдХреЛ рдЯреИрдЧ, рд╢рд╣рд░ рдФрд░ рдХрдВрдкрдирд┐рдпреЛрдВ рджреНрд╡рд╛рд░рд╛ рдЫреВрдЯ рдЦреЛрдЬ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдлрд╝рд╛рдЗрд▓ рдореЗрдВ 3 рдорд╛рд░реНрдЧреЛрдВ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди / routes.php рддреБрд░рдВрдд рдмрд╛рдж home:

 // app/routes.php ... Route::get('by_tag/{name}', array('as' => 'home.by_tag', 'uses' => 'HomeController@byTag'))->where('name', '[A-Za-z0-9 -_]+'); Route::get('by_city/{name}', array('as' => 'home.by_city', 'uses' => 'HomeController@byCity'))->where('name', '[A-Za-z0-9 -_]+'); Route::get('by_company/{name}', array('as' => 'home.by_company', 'uses' => 'HomeController@byCompany'))->where('name', '[A-Za-z0-9 -_]+'); ... 

рдЕрдм рд▓рд╛рдкрддрд╛ рддрд░реАрдХреЛрдВ рдХреЛ рдЗрд╕рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ HomeController:

 // app/controllers/HomeController.php ... /** * Display a listing of offers that belongs to tag. * * @param string $name * @return Response */ public function byTag($name) { $tag = Tag::whereName($name)->firstOrFail(); $offers = $tag->offers; $title = "Offers tagged as: " . $tag->name; return View::make('home.index', compact('offers', 'title')); } /** * Display a listing of offers that belongs to city. * * @param string $name * @return Response */ public function byCity($name) { $city = City::whereName($name)->firstOrFail(); $offers = $city->offers; $title = "Offers in: " . $city->name; return View::make('home.index', compact('offers', 'title')); } /** * Display a listing of offers that belongs to company. * * @param string $name * @return Response */ public function byCompany($name) { $company = Company::whereName($name)->firstOrFail(); $offers = $company->offers; $title = "Offers by: " . $company->name; return View::make('home.index', compact('offers', 'title')); } ... 

рдЗрди рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЗ рд╕рд╣реА рд╕рдВрдЪрд╛рд▓рди рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдореЙрдбрд▓ рдореЗрдВ рд╕рдВрдмрдВрдз рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ City, CompanyрдФрд░ Tag:

 // app/models/City.php ... public function offers() { return $this->hasMany('Offer'); } // app/models/Company.php ... public function offers() { return $this->hasMany('Offer'); } // app/models/Tag.php ... public function offers() { return $this->belongsToMany('Offer'); } 

рдЗрд╕ рдкреВрд░реА рдЪреАрдЬрд╝ рдХреЛ рдЦреЗрд▓рдиреЗ рдХреЗ рд▓рд┐рдП, рд▓рд┐рдВрдХ рдЬреЛрдбрд╝рдХрд░ рдлрд╝рд╛рдЗрд▓ рдРрдк / рд╡рд┐рдЪрд╛рд░ / рдСрдлрд╝рд░ / _preview.blade.php рдмрджрд▓реЗрдВ :

 // app/views/offers/_preview.blade.php <a class="image-container" href="{{ route('home.offer', $offer->id) }}"> <img src=""> </a> <div class="caption"> <h3>{{{ $offer->title }}}</h3> <hr> <p class="description">{{ $offer->webDescription() }}</p> <hr> <p><span class="label label-important">{{{ $offer->off }}} % off</span></p> <p>Location: <a href="{{ route('home.by_city', $offer->city->name) }}">{{{ $offer->city->name }}}</a></p> <p>Offer by: <a href="{{ route('home.by_company', $offer->company->name) }}">{{{ $offer->company->name }}}</a></p> <p>Expires on: <span class="label label-warning">{{{ $offer->expires }}}</span></p> <p>Tags: @foreach($offer->tags as $tag) <a class="no_decoration" href="{{ route('home.by_tag', $tag->name) }}"> <span class="badge">{{{$tag->name}}}</span> </a> @endforeach </p> </div> 

рд╣рдо рдХреНрд▓рд┐рдХ рдХрд░рддреЗ рд╣реИрдВ, рдЬрд╛рддреЗ рд╣реИрдВ, рдЫреВрдЯ рдХреЛ рдХреНрд░рдордмрджреНрдз рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдорд╛рдкрджрдВрдб рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рдЕрдм рдПрдХ рдЕрд▓рдЧ рдЫреВрдЯ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд░рд╕реНрддреБрддрд┐ рджреЗрдВ:

 // app/views/offers/_show.blade.php @extends('layouts.main') @section('main') <div class="page-header"> <h1> <span class="label label-important label-big">{{{ $offer->off }}}%</span> {{{ $offer->title }}} <small> by <a href="{{{ route('home.by_company', $offer->company->name) }}}">{{{ $offer->company->name }}}</a> </small> </h1> </div> <div class="pull-left image-container-big"> <img class="img-rounded" src="" alt="{{{ $offer->title }}}"> </div> <div class="description"> <p>{{ $offer->webDescription() }}</p> </div> <div class="clearfix"></div> <hr> <p>Location: <a href="{{ route('home.by_city', $offer->city->name) }}">{{{ $offer->city->name }}}</a> </p> <p>Tags: @foreach($offer->tags as $tag) <a class="no_decoration" href="{{ route('home.by_tag', $tag->name) }}"> <span class="badge">{{{$tag->name}}}</span> </a> @endforeach </p> <hr> <div class="page-header"> <h3>User's comments <small>leave and yours one</small></h3> </div> {{ Form::open() }} {{ Form::textarea('body', Input::old('body'), array('class' => 'input-block-level', 'style' => 'resize: vertical;'))}} <div class="input-append"> {{ Form::select('mark', array(0 => 5, 1 => 4, 2 => 3, 3 => 2, 4 => 1), Input::old('mark', 0)) }} {{ Form::submit('Comment', array('class' => 'btn btn-success', 'style' => 'clear: both;')) }} </div> {{ Form::close() }} @include('partials.errors', $errors) @stop // public/css/main.css    body {padding-top: 60px;} .error {color: red;} .no_decoration:hover, .no_decoration:focus {text-decoration: none;} .thumbnail .image-container {width: 100%; max-height: 200px; overflow: hidden; display: block;} .thumbnail .image-container img {min-width: 100%; min-height: 100%;} .thumbnail h3 {height: 40px; overflow: hidden;} .thumbnail .description {height: 100px; overflow: hidden;} .image-container-big {width: 500px; height: 300px; margin: 0 20px 20px 0; text-align: center;} .image-container-big img {max-height: 300px; margin: 0 auto;} .label.label-big {font-size: 32px; line-height: 1.5em; padding: 0 15px; margin-bottom: 5px;} 

рдкреВрд░реНрдг рд░реВрдк рд╕реЗ рдЫреВрдЯ рджреЗрдЦрдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ рдорд╛рд░реНрдЧ рдФрд░ рдПрдХ рд╡рд┐рдзрд┐ рдЬреЛрдбрд╝ рджреЗрдВрдЧреЗ, рдФрд░ рдЕрдВрдд рдореЗрдВ рдореИрдВрдиреЗ рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдлрд╝реЙрд░реНрдо рдЬреЛрдбрд╝рд╛ред рдЗрд╕рдХреА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рд╡рд╛рдВрдЫрд┐рдд рдирд┐рдпрдВрддреНрд░рдХ рдореЗрдВ рдорд╛рд░реНрдЧ рдФрд░ рд╡рд┐рдзрд┐ рдХреЛ рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛:

 // app/routes.php ... Route::get('offer_{id}', array('as' => 'home.offer', 'uses' => 'HomeController@showOffer'))->where('id', '[0-9]+'); Route::post('offer_{id}', array('before' => 'not_guest', 'uses' => 'HomeController@commentOnOffer'))->where('id', '[0-9]+'); ... Route::filter('not_guest', function(){ if (Auth::guest()) { return Redirect::back()->withInput()->with('message', 'You should be logged in to provide this action.'); } }); // app/controllers/HomeController.php ... /** * Display an offer. * * @param int $id * @return Response */ public function showOffer($id) { $offer = Offer::findOrFail($id); return View::make('offers._show', compact('offer')); } /** * Storing comment on offer. * * @param int $id * @return Response */ public function commentOnOffer($id) { $offer = Offer::findOrFail($id); if ($offer->usersComments->contains(Auth::user()->id)) { return Redirect::back()->withInput()->with('message', 'You have already commented on this Offer'); } $rules = array('body' => 'required|alpha|min:10|max:500', 'mark' => 'required|numeric|between:1,5'); $validator = Validator::make(Input::all(), $rules); if ($validator->passes()) { $offer->usersComments()->attach(Auth::user()->id, array('body' => Input::get('body'), 'mark' => Input::get('mark'))); return Redirect::back(); } return Redirect::back()->withInput()->withErrors($validator); } ... 

рдЪрд▓реЛ рд╕рдм рдХреБрдЫ рдХреЗ рд╕рд╛рде рд╕реМрджрд╛ рдХрд░рддреЗ рд╣реИрдВ:

рдбрд┐рд╕реНрдХрд╛рдЙрдВрдЯ рдкреЗрдЬ рдкрд░ рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдлрд╝рд╛рдЗрд▓ рдРрдк / рд╡рд┐рдЪрд╛рд░ / рдСрдлрд╝рд░ / _show.blade.php рдХреЛ рдереЛрдбрд╝рд╛ рдмрджрд▓реЗрдВ

 // app/views/offers/_show.blade.php ... @if(!$offer->usersComments->count()) <div class="well">You can be first to comment on this offer!</div> @endif @if(Auth::guest() || (!Auth::guest() && !$offer->usersComments->contains(Auth::user()->id))) {{ Form::open() }} {{ Form::textarea('body', Input::old('body'), array('class' => 'input-block-level', 'style' => 'resize: vertical;'))}} <div class="input-append"> {{ Form::select('mark', array(5 => 5, 4 => 4, 3 => 3, 2 => 2, 1 => 1), Input::old('mark', 5)) }} {{ Form::submit('Comment', array('class' => 'btn btn-success', 'style' => 'clear: both;')) }} </div> {{ Form::close() }} @include('partials.errors', $errors) @endif @foreach($offer->usersComments as $user) <div class="media"> <a class="pull-left" href="#"> <img class="media-object" data-src="holder.js/64x64"> </a> <div class="media-body"> <h4 class="media-heading">{{{ $user->username }}} <span class="label label-success">mark: {{{ $user->pivot->mark }}}</span></h4> <p class="muted">{{ str_replace("\r\n", '<br>', e($user->pivot->body)) }}</p> </div> </div> @endforeach @stop 

рдЕрдм, рдЫреВрдЯ рдХреЗ рддрд╣рдд, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдкрдиреА рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдХреЛ рдПрдХ рдмрд╛рд░ рдореЗрдВ рдЫреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдпрджрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдиреЗ рдкрд╣рд▓реЗ рд╣реА рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдЫреЛрдбрд╝ рджреА рд╣реИ, рддреЛ рдЙрд╕рдХреЗ рд▓рд┐рдП рдлреЙрд░реНрдо рдкреНрд░рджрд░реНрд╢рд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред

рдЕрдЧрд▓рд╛ рдХрджрдо рд╕рд╛рдЗрдЯ рддрдХ рдкрд╣реБрдВрдЪ рдЕрдзрд┐рдХрд╛рд░ рдЖрд╡рдВрдЯрд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдкрд╣рд▓реЗ, рд╣рдо рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдФрд░ рднреВрдорд┐рдХрд╛рдУрдВ рдХреЗ рдмреАрдЪ рд╕рдВрдмрдВрдз рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░реЗрдВрдЧреЗ:

 // app/models/User.php ... public function roles() { return $this->belongsToMany('Role'); } ... 

рдЕрдЧрд▓рд╛, рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдкреИрдирд▓ рдореЗрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рднреВрдорд┐рдХрд╛ рдкреНрд░рдмрдВрдзрди рдЬреЛрдбрд╝реЗрдВ:

 // app/routes.php ... Route::group(array('before' => 'admin.auth'), function() { ... Route::resource('users', 'UsersController'); Route::post('upload', array('uses' => 'HomeController@uploadOfferImage')); }); ... // app/views/layouts/scaffold.blade.php ... <li>{{ link_to_route('users.index', 'Users') }}</li> <li class="pull-right">{{ link_to_route('login.logout', 'Logout') }}</li> ... 

рдпрд╛рдж рд░рдЦреЗрдВ рдХрд┐ рдореЙрдбрд▓ рдореЗрдВ UserрдЖрдкрдХреЛ рднреВрдорд┐рдХрд╛рдУрдВ рдХреЗ рд╕рд╛рде рдПрдХ рд░рд┐рд╢реНрддрд╛ рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛:

 // app/models/User.php ... public function roles() { return $this->belongsToMany('Role'); } ... 

рдПрдХ рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛рдПрдБ UserController:

 // app/controllers/UsersController.php class UsersController extends BaseController { /** * User Repository * * @var User */ protected $user; public function __construct(User $user) { $this->user = $user; } /** * Display a listing of the resource. * * @return Response */ public function index() { $users = $this->user->all(); return View::make('users.index', compact('users')); } /** * Display the specified resource. * * @param int $id * @return Response */ public function show($id) { $user = $this->user->findOrFail($id); return View::make('users.show', compact('user')); } /** * Show the form for editing the specified resource. * * @param int $id * @return Response */ public function edit($id) { $user = $this->user->findOrFail($id); return View::make('users.edit', compact('user')); } /** * Update the specified resource in storage. * * @param int $id * @return Response */ public function update($id) { $user = $this->user->findOrFail($id); $roles = array(); foreach (explode(', ', Input::get('roles')) as $role_name) { if ($role = Role::where('role', '=', $role_name)->first()) { $roles[] = $role->id; } } $user->roles()->sync($roles); return Redirect::route('users.show', $id); } /** * Remove the specified resource from storage. * * @param int $id * @return Response */ public function destroy($id) { $this->user->findOrFail($id)->delete(); return Redirect::route('users.index'); } } 

рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рд╡рд┐рдЪрд╛рд░ / рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдлрд╝реЛрд▓реНрдбрд░ рдмрдирд╛рдПрдВ рдФрд░ рд╡рд╣рд╛рдВ 3 рдлрд╛рдЗрд▓реЗрдВ рдЬреЛрдбрд╝реЗрдВ:

 // app/views/users/index.blade.php @extends('layouts.scaffold') @section('main') <h1>All Users</h1> @if ($users->count()) <table class="table table-striped table-bordered"> <thead> <tr> <th>Username</th> <th>Email</th> <th>Roles</th> </tr> </thead> <tbody> @foreach ($users as $user) <tr> <td>{{{ $user->username }}}</td> <td>{{{ $user->email }}}</td> <td> @foreach($user->roles as $role) <span class="badge">{{{$role->role}}}</span> @endforeach </td> <td>{{ link_to_route('users.edit', 'Edit', array($user->id), array('class' => 'btn btn-info')) }}</td> <td> {{ Form::open(array('method' => 'DELETE', 'route' => array('users.destroy', $user->id))) }} {{ Form::submit('Delete', array('class' => 'btn btn-danger')) }} {{ Form::close() }} </td> </tr> @endforeach </tbody> </table> @else There are no users @endif @stop // app/views/users/show.blade.php @extends('layouts.scaffold') @section('main') <h1>Show User</h1> <p>{{ link_to_route('users.index', 'Return to all users') }}</p> <table class="table table-striped table-bordered"> <thead> <tr> <th>Username</th> <th>Email</th> <th>Roles</th> </tr> </thead> <tbody> <tr> <td>{{{ $user->username }}}</td> <td>{{{ $user->email }}}</td> <td> @foreach($user->roles as $role) <span class="badge">{{{ $role->role }}}</span> @endforeach </td> <td>{{ link_to_route('users.edit', 'Edit', array($user->id), array('class' => 'btn btn-info')) }}</td> <td> {{ Form::open(array('method' => 'DELETE', 'route' => array('users.destroy', $user->id))) }} {{ Form::submit('Delete', array('class' => 'btn btn-danger')) }} {{ Form::close() }} </td> </tr> </tbody> </table> @stop // app/views/users/edit.blade.php @extends('layouts.scaffold') @section('main') <h1>Edit User</h1> {{ Form::model($user, array('method' => 'PATCH', 'route' => array('users.update', $user->id))) }} <ul> <li> {{ Form::label('username', 'Username:') }} {{ Form::text('username', $user->username, array('disabled')) }} </li> <li> {{ Form::label('email', 'Email:') }} {{ Form::text('email', $user->email, array('disabled')) }} </li> <li> {{ Form::label('roles', 'Roles:') }} {{ Form::text('roles', Input::old('roles', implode(', ', array_fetch($user->roles()->get(array('role'))->toArray(), 'role')))) }} </li> <li> {{ Form::submit('Update', array('class' => 'btn btn-info')) }} {{ link_to_route('users.show', 'Cancel', $user->id, array('class' => 'btn')) }} </li> </ul> {{ Form::close() }} @if ($errors->any()) <ul> {{ implode('', $errors->all('<li class="error">:message</li>')) }} </ul> @endif @stop @section('scripts') <script> $(document).ready(function(){ function split( val ) { return val.split( /,\s*/ ); } function extractLast( term ) { return split( term ).pop(); } $( "#roles" ) // don't navigate away from the field on tab when selecting an item .bind( "keydown", function( event ) { if ( event.keyCode === $.ui.keyCode.TAB && $( this ).data( "ui-autocomplete" ).menu.active ) { event.preventDefault(); } }) .autocomplete({ source: function( request, response ) { $.getJSON( "/roles", { term: extractLast( request.term ), }, function( data ) { response($.map(data, function(item) { return { value: item.role } })) } ); }, search: function() { // custom minLength var term = extractLast( this.value ); if ( term.length < 2 ) { return false; } }, focus: function() { // prevent value inserted on focus return false; }, select: function( event, ui ) { console.log(ui); console.log(this); var terms = split( this.value ); // remove the current input terms.pop(); // add the selected item terms.push( ui.item.value ); // add placeholder to get the comma-and-space at the end terms.push( "" ); this.value = terms.join( ", " ); return false; } }); }); </script> @stop 

рдФрд░ рдереЛрдбрд╝рд╛ рдореЗрдЯрд╛ indexрдХрдВрдЯреНрд░реЛрд▓рд░ рднреА рдмрджрд▓реЗрдВRolesController

  ... public function index() { $roles = $this->role->all(); if (Request::ajax()) { $roles = Role::where('role', 'like', '%'.Input::get('term', '').'%')->get(array('id', 'role')); return $roles; } return View::make('roles.index', compact('roles')); } ... 

рдЕрдм рд╕реНрд╡рддрдГ рдкреВрд░реНрдг рд╣реЛрдиреЗ рд╡рд╛рд▓реЗ рдХрд╛рд░реНрдпред

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЗрд╕ рдЖрджреЗрд╢ рдореЗрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреЛрдИ рд╡рд┐рд╕рдВрдЧрддрд┐рдпрд╛рдВ рдирд╣реАрдВ рд╣реИрдВ, рд╣рдо рд╕рднреА рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдХреЛ рд╡рд╛рдкрд╕ рд░реЛрд▓ рдХрд░реЗрдВрдЧреЗ рдФрд░ рдЙрд╕ рдЙрддреНрдХреГрд╖реНрдЯ рдЙрдкрдХрд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ рдЬреЛ рд╣рдореЗрдВ рдЗрд╕рдХреЗ рд╕рд╛рде рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ Laravel- рдпрд╣ рд╣реИ рдбреЗрдЯрд╛рдмреЗрд╕рд╕рд╛рдЗрдбрд░ ред рдЗрд╕рдХреЗ рд╕рд╛рде, рд╣рдо рдЕрдкрдиреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рдХреБрдЫ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЗ рд╕рд╛рде рднрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╛ рдбреЗрдЯрд╛ рд╢реБрд░реВ / рдкрд░реАрдХреНрд╖рдг рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдкрд╣рд▓реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рдбреЗрдЯрд╛рдмреЗрд╕ / рдмреАрдЬUsersTableSeeder рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рдПрдХ рдХреНрд▓рд╛рд╕ рдмрдирд╛рдПрдВ :

 // app/database/seeds/UsersTableSeeder.php class UsersTableSeeder extends Seeder { public function run() { $users = array( array( 'username' => 'habrahabr', 'email' => 'habrahabr@habr.com', 'password' => Hash::make('habr'), 'updated_at' => DB::raw('NOW()'), 'created_at' => DB::raw('NOW()'), ) ); DB::table('users')->insert($users); } } 

рддрд░реНрдХ рдпрд╣ рд╣реИ: рд╣рдо рддрд╛рд▓рд┐рдХрд╛ рдХреЛ рд╕рд╛рдлрд╝ рдХрд░рддреЗ рд╣реИрдВ, рдбреЗрдЯрд╛ рдХреА рдПрдХ рд╕рд░рдгреА рдмрдирд╛рддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рд╕рдореНрдорд┐рд▓рд┐рдд рдХрд░рддреЗ рд╣реИрдВред

рдХреЗ рд╕рд╛рде рдРрд╕рд╛ рд╣реА рдХрд░рддреЗ рд╣реИрдВ RolesTableSeeder:

 // app/database/seeds/RolesTableSeeder.php class RolesTableSeeder extends Seeder { public function run() { $roles = array( array( 'role' => 'admin', 'updated_at' => DB::raw('NOW()'), 'created_at' => DB::raw('NOW()') ), array( 'role' => 'manager', 'updated_at' => DB::raw('NOW()'), 'created_at' => DB::raw('NOW()') ), array( 'role' => 'moderator', 'updated_at' => DB::raw('NOW()'), 'created_at' => DB::raw('NOW()') ) ); DB::table('roles')->insert($roles); } } 

рдпрд╣рд╛рдВ рдореИрдВрдиреЗ рднреВрдорд┐рдХрд╛рдПрдВ рднреА рдЬреЛрдбрд╝реАрдВ managerрдФрд░ moderatorрдЗрди рднреВрдорд┐рдХрд╛рдУрдВ рдХреЗ рд╕рд╛рде рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдкреИрдирд▓ рдореЗрдВ рд╡реНрдпрдХреНрддрд┐рдЧрдд рд╕рдВрд╕рд╛рдзрдиреЛрдВ рддрдХ рдкрд╣реБрдВрдЪ рдкреНрд░рджрд╛рди рдХреАред

рдЕрдЧрд▓рд╛, рдПрдХ рдФрд░ рд╡рд░реНрдЧ рдмрдирд╛рдПрдБ Seeder:

 // app/database/seeds/RoleUserTableSeeder.php class RoleUserTableSeeder extends Seeder { public function run() { // Uncomment the below to wipe the table clean before populating DB::table('role_user')->truncate(); $role_user = array( array('user_id' => 1, 'role_id' => 1) ); // Uncomment the below to run the seeder DB::table('role_user')->insert($role_user); } } 

рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдордиреЗ рднреВрдорд┐рдХрд╛ рдХреЛ adminрдЕрдкрдиреЗ рдкрд╣рд▓реЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдореЗрдВ рдЬреЛрдбрд╝рд╛ ред

рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рд╕рд╛рдлрд╝ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдФрд░ рдЗрд╕реЗ рд╣рдорд╛рд░реЗ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдбреЗрдЯрд╛ рд╕реЗ рднрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдкрд╣рд▓реЗ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдлрд╝рд╛рдЗрд▓ рдРрдк / рдбреЗрдЯрд╛рдмреЗрд╕ / рдмреАрдЬ / DatabaseSeeder.php рдХреЛ рдмрджрд▓реЗрдВ :

 // app/database/seeds/DatabaseSeeder class DatabaseSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { Eloquent::unguard(); //         $this->call('UsersTableSeeder'); $this->call('RolesTableSeeder'); $this->call('RoleUserTableSeeder'); } } 

рдФрд░ рд╕рднреА рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдХрдВрд╕реЛрд▓ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХрдорд╛рдВрдб рдЪрд▓рд╛рдПрдВ ( / рдХрд╛рд░реНрдпрдХреНрд╖реЗрддреНрд░ / php / habr / рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ ):

 php artisan migrate:refresh --seed 

migrate:refreshрд╕рднреА рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдХреЛ рд╡рд╛рдкрд╕ рд░реЛрд▓ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдлрд┐рд░ рдЙрдиреНрд╣реЗрдВ рдлрд┐рд░ рд╕реЗ рд╢реБрд░реВ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рд╡рд┐рдХрд▓реНрдк --seedрдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЖрдкрдХреЛ рднреА рдЪрд▓рд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ DatabaseSeederред

рдЕрдЧрд▓рд╛, рд╣рдо рдЕрдзрд┐рдХрд╛рд░реЛрдВ рдкрд░ рддрд░реНрдХ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░рддреЗ рд╣реИрдВред рдореЙрдбрд▓ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдХрд░реЗрдВ User:

 // app/models/User.php ... public function isAdmin() { $admin_role = Role::whereRole('admin')->first(); return $this->roles->contains($admin_role->id); } ... public function isManager() { $manager_role = Role::whereRole('manager')->first(); return $this->roles->contains($manager_role->id) || $this->isAdmin(); } ... public function isModerator() { $admin_role = Role::whereRole('admin')->first(); return $this->roles->contains($admin_role->id) || $this->isAdmin(); } ... public function isRegular() { $roles = array_filter($this->roles->toArray()); return empty($roles); } } 

рдЕрдЧрд▓рд╛, рд╣рдо рд░реВрдЯ рдлрд╝рд╛рдЗрд▓ рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рддрд╛рдХрд┐ рдпрд╣ рд╕рд╛рдЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рдЕрдзрд┐рдХрд╛рд░реЛрдВ рд╕реЗ рдореЗрд▓ рдЦрд╛рдП:

 // app/routes.php ... Route::post('offer_{id}', array('before' => 'not_guest|regular_user', 'uses' => 'HomeController@commentOnOffer'))->where('id', '[0-9]+'); ... Route::group(array('before' => 'admin.auth'), function() { Route::get('dashboard', function() { return View::make('dasboard'); }); Route::group(array('before' => 'manager_role_only'), function() { Route::resource('cities', 'CitiesController'); Route::resource('companies', 'CompaniesController'); Route::resource('tags', 'TagsController'); Route::resource('offers', 'OffersController'); Route::post('upload', array('uses' => 'HomeController@uploadOfferImage')); }); Route::resource('comments', 'CommentsController'); Route::group(array('before' => 'manager_role_only'), function() { Route::resource('roles', 'RolesController'); Route::resource('users', 'UsersController'); }); }); Route::when('comments*', 'moderator_role_only'); Route::filter('admin_role_only', function() { if (Auth::user()->isAdmin()) { return Redirect::intended('/')->withMessage('You don\'t have enough permissions to do that.'); } }); Route::filter('manager_role_only', function() { if (!Auth::user()->isManager()) { return Redirect::intended('/')->withMessage('You don\'t have enough permissions to do that.'); } }); Route::filter('moderator_role_only', function() { if (!Auth::user()->isModerator()) { return Redirect::intended('/')->withMessage('YYou don\'t have enough permissions to do that.'); } }); Route::filter('admin.auth', function() { if (Auth::guest()) { return Redirect::to('login'); } }); Route::filter('un_auth', function() { if (!Auth::guest()) { Auth::logout(); } }); Route::filter('not_guest', function(){ if (Auth::guest()) { return Redirect::intended('/')->withInput()->with('message', 'You should be logged in to provide this action.'); } }); Route::filter('regular_user', function(){ if (!Auth::guest()) { if (!Auth::user()->isRegular()) { return Redirect::back()->with('message', 'You cannot do that due to your role.'); } } }); 

рдЬреИрд╕рд╛ рдХрд┐ рдЖрдкрдиреЗ рджреЗрдЦрд╛, рдореИрдВрдиреЗ рдЯрд┐рдкреНрдкрдгреА рдорд╛рд░реНрдЧ рдореЗрдВ рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рдлрд╝рд┐рд▓реНрдЯрд░ рдЬреЛрдбрд╝рд╛ред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╕рд╛рдЗрдЯ рдХреЗ рд╕рд╛рдорд╛рдиреНрдп рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рдЫреЛрдбрд╝рдХрд░ рдХреЛрдИ рднреА рдЫреВрдЯ рдкрд░ рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдХреЛ рдЫреЛрдбрд╝рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдирд╣реАрдВ рд╣реЛрдЧрд╛ред

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдпрд╣рд╛рдВ рдПрдХ рдорд╛рд░реНрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ Route::when()- рдпрд╣ рддрдерд╛рдХрдерд┐рдд рдкреИрдЯрд░реНрди рдлрд╝рд┐рд▓реНрдЯрд░ рд╣реИ ред рдпрд╣ рдЖрдкрдХреЛ рдкрд╣рд▓реЗ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ URLрд░реВрдк рдореЗрдВ рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЛ рдкрд╛рд╕ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ , рдЬрд┐рд╕ рдлрд╝рд┐рд▓реНрдЯрд░ рдХреЛ рдЖрдк рджреВрд╕рд░реЗ рдХреЗ рд░реВрдк рдореЗрдВ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рдФрд░ рдпрд╣ рд╡рд╣ рд╕рд░рдгреА рд▓реЗ рд╕рдХрддрд╛ рд╣реИ HTTP рдЬрд┐рд╕рд╕реЗ рдЖрдк рдлрд╝рд┐рд▓реНрдЯрд░ рдХреЛ рддреАрд╕рд░реЗ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд░реВрдк рдореЗрдВ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рдирд┐рдпрдВрддреНрд░рдХ

рд╡рд┐рдзрд┐ рдмрджрд▓реЗрдВ :login()LoginController

 // app/controllers/LoginController.php ... public function login() { if (Auth::attempt(array('email' => Input::get('email'), 'password' => Input::get('password')), true) || Auth::attempt(array('username' => Input::get('email'), 'password' => Input::get('password')), true)) { if (!Auth::user()->isRegular()) { return Redirect::to('dashboard'); } return Redirect::intended('/'); } return Redirect::back()->withInput(Input::except('password'))->with('message', 'Wrong creadentials!'); } 

рдЕрдм, рд╕рд╛рдЗрдЯ рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рддреЗ рд╕рдордп, рд╕рд╛рдорд╛рдиреНрдп рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рдореБрдЦреНрдп рдкреГрд╖реНрда рдкрд░ рдкреБрдирдГ рдирд┐рд░реНрджреЗрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдФрд░ рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдкреИрдирд▓ рдореЗрдВ рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ, рдордзреНрдпрд╕реНрде рдФрд░ рдкреНрд░рдмрдВрдзрдХред

рдкреНрд░рд╢рд╛рд╕рди рдХреЗ рд▓рд┐рдП рдиреЗрд╡рд┐рдЧреЗрд╢рди рдореЗрдиреВ рдХреЛ рдереЛрдбрд╝рд╛ рдмрджрд▓реЗрдВ:

 // app/views/layouts/scaffold.blade.php @if(!Auth::guest()) <ul class="nav nav-pills"> @if(Auth::user()->isManager()) <li>{{ link_to_route('offers.index', 'Offers') }}</li> <li>{{ link_to_route('companies.index', 'Companies') }}</li> <li>{{ link_to_route('tags.index', 'Tags') }}</li> <li>{{ link_to_route('cities.index', 'Cities') }}</li> @endif @if(Auth::user()->isModerator()) <li>{{ link_to_route('comments.index', 'Comments') }}</li> @endif @if(Auth::user()->isAdmin()) <li>{{ link_to_route('roles.index', 'Roles') }}</li> <li>{{ link_to_route('users.index', 'Users') }}</li> @endif <li class="pull-right">{{ link_to_route('login.logout', 'Logout') }}</li> </ul> @endif 

рдЙрддреНрдХреГрд╖реНрдЯ - рдЕрдм рдкреНрд░рддреНрдпреЗрдХ рднреВрдорд┐рдХрд╛ рдЙрди рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЛ рджреЗрдЦреЗрдЧрд╛ рдЬрд┐рдирдХреЗ рдкрд╛рд╕ рдЙрдирдХреА рдкрд╣реБрдВрдЪ рд╣реИред

рдИрдореЗрд▓

рдПрдХ рд╡реЗрдм рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдХреЗ рд▓рд┐рдП рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдкрд╣рд▓реВ рдореЗрд▓ рднреЗрдЬ рд░рд╣рд╛ рд╣реИред рдкрддреНрд░ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП

LaravelрдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ SwiftMailerрд╣реИ ( рд▓рд╛рд░рд╡реЗрд▓ рдореЗрд▓ )ред

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рдЖрдкрдХреЛ рдореЗрд▓ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдкрддреНрд░ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд░рджрд░реНрд╢рди рдХреЗ рд░реВрдк рдореЗрдВ, рдореИрдВ рдЕрдкрдиреЗ рдЦрд╛рддреЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реВрдВрдЧрд╛ gmail, рд▓реЗрдХрд┐рди рдЖрдк рдЕрдирд┐рд╡рд╛рд░реНрдп рд░реВрдк рд╕реЗ рдХрд┐рд╕реА рднреА рд╕реЗрд╡рд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдЕрдкрдиреЗ рд╕рд░реНрд╡рд░ рд╕реЗ рдореЗрд▓ рднреЗрдЬрдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдкреЛрд╕реНрдЯрдорд╛рд░реНрдХрдкреНрдк )ред

рдореЗрд▓ рд╕реЗрдЯрдЕрдк:

 // app/config/mail.php ... return array( ... 'driver' => 'smtp', ... 'host' => 'smtp.gmail.com', ... 'port' => 587, ... 'from' => array('address' => 'habrahabr@habr.com', 'name' => 'Habra Offers'), ... 'encryption' => 'tls', ... 'username' => 'mygmailaccount@gmail.com', ... 'password' => 'mypassword', ... 'pretend' => false ); 

pretendрд╕рдВрджреЗрд╢ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдкреИрд░рд╛рдореАрдЯрд░ рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИред рдпрджрд┐ рдпрд╣ рд╕рд╣реА рдкрд░ рд╕реЗрдЯ рд╣реИ , рддреЛ рдИрдореЗрд▓ рдирд╣реАрдВ рднреЗрдЬреЗ рдЬрд╛рдПрдВрдЧреЗ, рд▓реЗрдХрд┐рди рд░рд┐рдкреЛрд░реНрдЯ рднреЗрдЬрдирд╛ рд╕рд╛рдЗрдЯ рдХреЗ рд▓реЙрдЧ ( рдРрдк / рд╕реНрдЯреЛрд░реЗрдЬ / рд▓реЙрдЧ ) рдореЗрдВ рд╕рд╣реЗрдЬрд╛ рдЬрд╛рдПрдЧрд╛ред

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдореИрдВ рдкрдВрдЬреАрдХрд░рдг рдХреЗ рджреМрд░рд╛рди рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реНрд╡рд╛рдЧрдд рдпреЛрдЧреНрдп рдИрдореЗрд▓ рднреЗрдЬрдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ, рдЗрд╕рдХреЗ рд▓рд┐рдП рдореИрдВ рдРрдк / рд╡рд┐рдЪрд╛рд░ / рдИрдореЗрд▓ рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рдПрдХ рдЯреЗрдореНрдкрд▓реЗрдЯ рдмрдирд╛рдКрдВрдЧрд╛ :

 // app/views/emails/welcome.blade.php <!DOCTYPE html> <html lang="en-US"> <head> <meta charset="utf-8"> </head> <body> <h1>Welcome to Habra Offers!</h1> <div> We are glad that you are interested in us, {{{ $username }}}! </div> </body> </html> 

рдЕрдЧрд▓рд╛, store()рд╣рдорд╛рд░реА рд╡рд┐рдзрд┐ рдмрджрд▓реЗрдВ LoginController:

 // app/controllers/LoginController.php ... $user->save(); Mail::send('emails.welcome', array('username' => $user->username), function($message) use ($user) { $message->to($user->email, $user->username)->subject('Welcome to Habra Offers!'); }); Auth::loginUsingId($user->id); ... 

рдореЗрд▓ рд╡рд░реНрдЧ send()рддреАрди рддрд░реНрдХ рд▓реЗрдиреЗ рд╡рд╛рд▓реЗ рдореЗрд▓ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ :

рд▓реЗрдХрд┐рди рдПрдХ рд╕реНрд╡рд╛рдЧрдд рдкрддреНрд░ рдХреЗрд╡рд▓ рдПрдХ рдкреНрд░рдХрд╛рд░ рдХрд╛ рдкрддреНрд░ рдирд╣реАрдВ рд╣реИ рдЬрд┐рд╕рдХреА рд╣рдореЗрдВ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдХреНрдпрд╛ рд╣реЛрдЧрд╛ рдпрджрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдкрдирд╛ рдкрд╛рд╕рд╡рд░реНрдб рднреВрд▓ рдЧрдпрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рдкреБрдирд░реНрдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реИ? рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдкрд╛рд╕рд╡рд░реНрдб рдЕрдиреБрд╕реНрдорд╛рд░рдХ рдФрд░ рд░реАрд╕реЗрдЯLaravel рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ ред рд╣рдореЗрдВ рдХреНрдпрд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:


 cd /workspace/php/habr php artisan auth:reminders php artisan migrate 

рдкрд╛рд╕рд╡рд░реНрдб рдХреЛ рдкреБрдирд░реНрдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ рдХреЙрд▓ рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ Password::remind(array('email' => $email))рдФрд░ рдкрд╛рд╕рд╡рд░реНрдб рд░реАрд╕реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд▓рд┐рдВрдХ рдХреЗ рд╕рд╛рде рдПрдХ рдИрдореЗрд▓ рднреЗрдЬрд╛ рдЬрд╛рдПрдЧрд╛ред

рд╣рдореЗрдВ 2 рдЯреЗрдореНрдкреНрд▓реЗрдЯ рдмрдирд╛рдиреЗ рд╣реЛрдВрдЧреЗ:

рдПрдХ рдлрд╝рдВрдХреНрд╢рди trans()рдПрдХ рд╕рд╣рд╛рдпрдХ рдлрд╝рдВрдХреНрд╢рди рд╣реИ рдЬреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рд╕реЗ рд╕реНрдерд╛рдиреАрдпрдХреГрдд рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рдЖрдЙрдЯрдкреБрдЯ рдХрд░рддрд╛ рд╣реИред рдЖрдк рдРрдк / рд▓реИрдВрдЧ / рдПрди / рд░рд┐рдорд╛рдЗрдВрдбрд░реНрд╕.рдлреИрдк рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдХреНрдпрд╛ рддреНрд░реБрдЯрд┐рдпрд╛рдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рд╣реЛ рд╕рдХрддреА рд╣реИрдВред рд╕реНрдерд╛рдиреАрдпрдХрд░рдг рдХреЛ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд░реВрд╕реА рднрд╛рд╖рд╛, рдЖрдк рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА рдПрдкреНрд▓рд┐рдХреЗрд╢рди / config / app.php рдореВрд▓реНрдп рд╕реНрдерд╛рди рдХреЗ рд▓рд┐рдП рдПрди рдХреЛ рдЖрд░рдпреВ рдФрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдлрд╝реЛрд▓реНрдбрд░ рдЬреЛрдбрд╝рдиреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рд▓реИрдВрдЧ / рдЖрд░рдпреВ , рдЬреЛ рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рдлрд╝рд╛рдЗрд▓реЗрдВ рдкреБрди: рдмрдирд╛рдиреЗ, рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рд▓реИрдВрдЧ / hi ред


рдЕрдЧрд▓рд╛, 4 рдорд╛рд░реНрдЧ рдЬреЛрдбрд╝реЗрдВ:

 // app/routes.php ... Route::group(array('before' => 'un_auth'), function() { ... Route::get('password/remind', array('as' => 'password.remind', 'uses' => 'LoginController@showReminderForm')); Route::post('password/remind', array('uses' => 'LoginController@sendReminder')); Route::get('password/reset/{token}', array('as' => 'password.reset', 'uses' => 'LoginController@showResetForm')); Route::post('password/reset/{token}', array('uses' => 'LoginController@resetPassword')); }); ... 

рдкреБрдирд░реНрдкреНрд░рд╛рдкреНрддрд┐ рдкрд░ рд╕реНрд╡рд┐рдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рд▓реЙрдЧрд┐рди рдкреГрд╖реНрда рдкрд░ рдПрдХ рд▓рд┐рдВрдХ рднреА рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ:

 // app/views/login/index.blade.php ... {{ Form::close() }} <p>{{ link_to_route('password.remind', 'Forgot password?') }}</p> ... 

рд╕рд╛рде рд╣реА рд▓рд╛рдкрддрд╛ рддрд░реАрдХреЗ LoginController:

 // app/controllers/LoginController.php ... /** * Show reminder form. * * @return Response */ public function showReminderForm() { return View::make('auth.remind'); } /** * Send reminder email. * * @return Response */ public function sendReminder() { $credentials = array('email' => Input::get('email')); return Password::remind($credentials, function($message, $user) { $message->subject('Password Reminder on Habra Offers'); }); } /** * Show reset password form. * * @return Response */ public function showResetForm($token) { return View::make('auth.reset')->with('token', $token); } /** * Reset password. * * @return Response */ public function resetPassword($token) { $credentials = array('email' => Input::get('email')); return Password::reset($credentials, function($user, $password) { $user->password = Hash::make($password); $user->save(); Auth::loginUsingId($user->id); return Redirect::home()->with('message', 'Your password has been successfully reseted.'); }); } 

рдЕрдм рдХреЛрдИ рднреА рдпреВрдЬрд░ рдЕрдкрдирд╛ рдкрд╛рд╕рд╡рд░реНрдб рд░реАрд╕реЗрдЯ рдХрд░ рд╕рдХрддрд╛ рд╣реИред

рдореБрдЦреНрдп рдкреГрд╖реНрда рдкрд░ рд╕рд╛рдЗрдЯ рдкрд░ рдкреНрд░рд╡реЗрд╢ рдХрд░рдиреЗ рдФрд░ рдкрдВрдЬреАрдХрд░рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдФрд░ рд▓рд┐рдВрдХ рдЬреЛрдбрд╝реЗрдВ:
 // app/views/layouts/main.blade.php ... <a class="brand" href="{{ route('home') }}">Habr Offers</a> <ul class="nav"> <li><a href="{{ route('home') }}">Home</a></li> </ul> <div class="btn-group pull-right"> @if(Auth::guest()) <a href="{{ route('login.index') }}" class="btn">Login</a> <a href="{{ route('login.register') }}" class="btn">Register</a> @else <a href="{{ route('login.logout') }}" class="btn">Logout</a> @endif </div> ... 

рдХреЗрд╡рд▓ рдЙрди рдЫреВрдЯреЛрдВ рдХреЗ рдкреГрд╖реНрдареЛрдВ рдкрд░ рдЖрдЙрдЯрдкреБрдЯ рдХреЛ рд╕реАрдорд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬреЛ рдЕрднреА рддрдХ рд╕рдорд╛рдкреНрдд рдирд╣реАрдВ рд╣реБрдП рд╣реИрдВ, рд╣рдореЗрдВ рдореЙрдбрд▓ рдореЗрдВ рдПрдХ рдФрд░ рд╡рд┐рдзрд┐ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА Offer:

 // app/controllers/Offer.php ... public function scopeActive($query) { return $query->where('expires', '>', DB::raw('NOW()')); } public function scopeSortLatest($query, $desc = true) { $order = $desc ? 'desc' : 'asc'; return $query->orderBy('created_at', $order); } ... 

рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдо рд╡рд┐рдзрд┐ рдореЗрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ HomeController@indexрдмрд╕ рдмрджрд▓рдиреЗ Offer::orderBy('created_at', 'desc')->get()рдкрд░ Offer::active()->sortLatest()->get()ред рд╣рдорд╛рд░реА рдирдИ рдмрдирд╛рдИ рдЧрдИ рд╡рд┐рдзрд┐ рдЙрди рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдХреЛ рдЬреЛрдбрд╝реЗрдЧреА рдЬрд┐рдиреНрд╣реЗрдВ рд╣рдореЗрдВ рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдХреА рд╢реНрд░реГрдВрдЦрд▓рд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╣рдо рдЯреИрдЧ, рд╢рд╣рд░реЛрдВ рдФрд░ рдХрдВрдкрдирд┐рдпреЛрдВ рджреНрд╡рд╛рд░рд╛ рдЫрдБрдЯрд╛рдИ рдХреЗ рддрд░реАрдХреЛрдВ рдХреЗ рд▓рд┐рдП рднреА рдРрд╕рд╛ рд╣реА рдХрд░реЗрдВрдЧреЗред

 // app/controllers/HomeController.php ... public function byTag($name) { ... $offers = $tag->offers()->active()->sortLatest()->get(); ... } 


рдкреГрд╖реНрда рдкрд░ рдЕрдВрдХ рд▓рдЧрд╛рдирд╛

рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдкрд╣рд▓реВ рдкреЗрдЬрд┐рдиреЗрд╢рди рд╣реИред рд╣рд╛рдВ, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдЖрдк рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рдХреНрд╡реЗрд░реА рднреЗрдЬ рд╕рдХрддреЗ рд╣реИрдВ, рдЙрддреНрддрд░ рдХреА рд╣рдЬрд╛рд░реЛрдВ рд▓рд╛рдЗрдиреЗрдВ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░ рдкреГрд╖реНрда рдкрд░ рдЙрди рд╕рднреА рдХреЛ рдзрдХреНрдХрд╛ рджреЗ рд╕рдХрддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдпрд╣ рд╢рд╛рдпрдж рд╣реА рдХрд┐рд╕реА рдХрд╛ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╣реИред рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рд▓реМрдЯрд╛рдП рдЧрдП рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЛ рд╕реАрдорд┐рдд рдХрд░рдирд╛ рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИ - рдХреНрд╡реЗрд░реА рдХреЗ рдЕрдВрдд рдореЗрдВ рдЖрдкрдХреЛ paginate()рдЗрд╕рдХреЗ рдмрдЬрд╛рдп рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ get(), рдпрд╛ all()ред рдПрдХ рд╕рд░рд▓ рдЙрджрд╛рд╣рд░рдг:

 // app/controllers/HomeController.php ... public function index() { $offers = Offer::active()->sortLatest()->paginate(); ... } ... // app/views/home/index.blade.php ... @if ($offers->count()) {{ $offers->links() }} ... {{ $offers->links() }} @else There are no offers @endif ... 

рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдХреЗрд╡рд▓ 15 рдкрд░рд┐рдгрд╛рдо рдПрдХ рдкреГрд╖реНрда рдкрд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рд╣реЛрдВрдЧреЗ, рдФрд░ рдиреАрдЪреЗ рдкреГрд╖реНрда рдиреЗрд╡рд┐рдЧреЗрд╢рди рд╣реЛрдЧрд╛ред рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдЖрд╕рд╛рдиреА рд╕реЗ рдкрд░рд┐рд╡рд░реНрддрдирд╢реАрд▓ рд╣реИ - рдмрд╕ рд╡рд╛рдВрдЫрд┐рдд рд╕рдВрдЦреНрдпрд╛ рдХреЛ рд╡рд┐рдзрд┐ рдореЗрдВ рдкрд╛рд╕ рдХрд░реЗрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, paginate(1)рдкреНрд░рддрд┐ рдкреГрд╖реНрда 1 рдкрд░рд┐рдгрд╛рдо рджреЗрдВред

 // app/controllers/HomeController.php ... public function byTag($name) { $tag = Tag::whereName($name)->firstOrFail(); $offers = $tag->offers()->active()->sortLatest()->paginate(); $title = "Offers tagged as: " . $tag->name; return View::make('home.index', compact('offers', 'title')); } ... public function byCity($name) { $city = City::whereName($name)->firstOrFail(); $offers = $city->offersr()->active()->sortLatest()->paginate(); $title = "Offers in: " . $city->name; return View::make('home.index', compact('offers', 'title')); } ... public function byCompany($name) { $company = Company::whereName($name)->firstOrFail(); $offers = $company->offers()->active()->sortLatest()->paginate(); $title = "Offers by: " . $company->name; return View::make('home.index', compact('offers', 'title')); } ... 

рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рднреА рдЬрдЯрд┐рд▓ рдирд╣реАрдВ рд╣реИред

рд╕реБрд╡рд┐рдзрд╛ рдХреЗ рд▓рд┐рдП, рд╣рдо рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдкреИрдирд▓ рдореЗрдВ рднреА рдРрд╕рд╛ рд╣реА рдХрд░реЗрдВрдЧреЗред

 // app/controllers/OffersController ... /** * Display a listing of the resource. * * @return Response */ public function index() { $offers = $this->offer->sortLatest()->paginate(); return View::make('offers.index', compact('offers')); } ... 

рдЕрдВрддрд┐рдо рдЪреАрдЬ рдЬрд┐рд╕реЗ рдЖрдк рд╕рд╛рдЗрдЯ рдкрд░ рдЬреЛрдбрд╝рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рд╡рд╣ рдкреГрд╖реНрдареЛрдВ рдФрд░ рдмреБрдХрдорд╛рд░реНрдХ рдкрд░ рдирд╡реАрдирддрдо рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдХреЛ рдЙрд╕ рдЫреВрдЯ рд╕реЗ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдирд╛ рд╣реИ рдЬрд┐рд╕ рдкрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдиреЗ рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдВ рдЫреЛрдбрд╝ рджреА рд╣реИрдВред

рдкреЗрдЬ рдлреНрд░реЗрдо рдореЗрдВ рдЯрд┐рдкреНрдкрдгреА рдЬреЛрдбрд╝рдХрд░ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ:

 // app/views/layouts/main.blade.php <div class="container"> @if (Session::has('message')) <div class="flash alert"> {{ Session::get('message') }} </div> @endif <div class="row-fluid"> <div class="span3"> <h2>Last Comments</h2> @if (count($comments = Comment::take(5)->get()) > 0) @foreach ($comments as $comment) @include('partials.comment', $comment) @endforeach @else There are no comments yet @endif </div> <div class="span9"> @yield('main') </div> </div> </div> 

рдФрд░ рд╕реНрд╡рдпрдВ рдЯреЗрдореНрдкрд▓реЗрдЯ рднреА рдмрдирд╛рдПрдВ comment:

 // app/views/partials/comment.blade.php <div class="well"> <a href="{{ route('home.offer', $comment->offer_id) }}"> {{ $comment->user->username }} <span class="label label-success pull-right">mark: {{ $comment->mark }}</span> </a> <div>{{ $comment->webBody() }}</div> </div> 

рдореЙрдбрд▓ Comment UserрдФрд░ рдХреЗ рдмреАрдЪ рд╕рдВрдмрдВрдз рдЬреЛрдбрд╝рдирд╛ рди рднреВрд▓реЗрдВ Offer:

 // app/models/Comment.php ... public function user() { return $this->belongsTo('User'); } public function offer() { return $this->belongsTo('Offer'); } public function webBody($options = array()) { $str = $this->body; if (isset($options['shorten'])) { $length = isset($options['length']) ? (int) $options['length'] : 50; $end = isset($options['end']) ? : 'тАж'; if (mb_strlen($str) > $length) { $str = mb_substr(trim($str), 0, $length); $str = mb_substr($str, 0, mb_strlen($str) - mb_strpos(strrev($str), ' ')); $str = trim($str.$end); } } $str = str_replace("\r\n", '<br>', e($str)); return $str; } ... 

рд╕рд╛рде рд╣реА html-рдЯрд┐рдкреНрдкрдгреА рдХреЛ рдХрдо рдХрд░рдиреЗ рдФрд░ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд╣рд╛рдпрдХ рдлрд╝рдВрдХреНрд╢рди ред

рдпрд╣ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП рдмреБрдХрдорд╛рд░реНрдХ рдЬреЛрдбрд╝рдирд╛ рдмрд╛рдХреА рд╣реИ:

 // app/routes.php Route::get('/', array('as' => 'home', 'uses' => 'HomeController@index')); Route::get('bookmarks', array('before' => 'auth', 'as' => 'home.bookmarks', 'uses' => 'HomeController@bookmarks')); ... // app/views/layouts/main.blade.php ... @if(Auth::guest()) <a href="{{ route('login.index') }}" class="btn">Login</a> <a href="{{ route('login.register') }}" class="btn">Register</a> @else <a href="{{ route('home.bookmarks') }}" class="btn">My Bookmarks</a> <a href="{{ route('login.logout') }}" class="btn">Logout</a> @endif ... // app/models/User.php ... public function usersOffers() { return $this->belongsToMany('Offer', 'comments')->withPivot('body', 'mark')->withTimestamps(); } ... // app/controllers/HomeController.php ... /** * Display a listing of bookmarked offers. * * @return Response */ public function bookmarks() { $offers = Auth::user()->usersOffers()->paginate(); $title = "My Bookmarked Offers"; return View::make('home.index', compact('offers', 'title')); } ... 

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдордиреЗ рдРрдк / рд░реВрдЯ.php рдореЗрдВ рд░реВрдЯ рдЬреЛрдбрд╝рд╛ , рдлрд┐рд░ рдРрдк / рд╡реНрдпреВ / рд▓реЗрдЖрдЙрдЯ / main.blade.php рдореЗрдВ рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рд▓рд┐рдВрдХ рдЬреЛрдбрд╝рд╛ , рдореЙрдбрд▓ UserрдФрд░ Offer, рдХреЗ рдмреАрдЪ рдХрдиреЗрдХреНрд╢рди рд╕реЗрдЯ рдХрд┐рдпрд╛ рдФрд░ рдЖрдЦрд┐рд░ рдореЗрдВ рд╣рдордиреЗ рдореЗрдердб рд▓рд╛рдЧреВ bookmarksрдХрд┐рдпрд╛ HomeControllerред

рддреИрдирд╛рддреА


рддреИрдирд╛рддреА рдХрд╛ рд╕рдордп рдЖ рдЧрдпрд╛ рд╣реИ! рдЗрд╕рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ fortrabbit.com рдХреЛ рдЪреБрдирд╛ - рдСрди рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд▓рд┐рдП рд╣реЛрд╕реНрдЯрд┐рдВрдЧ PHPред рдпрд╣ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИ Git, SSH, Memcached, Composer, MySQLрдФрд░ рдЕрдзрд┐рдХред

рд╡рд╣рд╛рдБ рдкрдВрдЬреАрдХрд░рдг рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИред



рдЗрд╕рдХреЗ рдмрд╛рдж, рдПрдХ рдирдпрд╛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рдПрдВред



рдЪрд▓реЛ рдЙрд╕реЗ рдмреБрд▓рд╛рддреЗ рд╣реИрдВ habrред рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХрд╛ рдирд╛рдо рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рд▓рд┐рдВрдХ рд╣реЛрдЧрд╛ habr.eu1.frbit.net/ ред рдПрдХ рдиреЛрдЯ (рд╣рд╛рдмрд░рд╛ рдСрдлрд░) рдЬреЛрдбрд╝реЗрдВ, рдФрд░ sshрдЕрдкрдиреА рдХрд╛рд░ рд╕реЗ рдЪрд╛рдмреА рдЬреЛрдбрд╝реЗрдВ ред рдЕрдкрдиреА sshрдХреБрдВрдЬреА рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП , рдЯрд░реНрдорд┐рдирд▓ рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░реЗрдВ:

 cat ~/.ssh/id_rsa.pub 




рдЕрдВрддрд┐рдо рдЪрд░рдг рдкрд░реНрдпрд╛рд╡рд░рдг рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЗ рд▓рд┐рдП рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдирд╛ рд╣реИред рдЖрдк рднрдВрдбрд╛рд░ рддрдХ рдЖрдкрдХреА рдкрд╣реБрдВрдЪ рдмрдиреЗрдЧреА Git, SSHрдФрд░ SFTP, MySQLрдЕрдиреБрдХреВрд▓рди рдФрд░ ReSyncрдЙрдкрдпреЛрдЧред

рдкрд░реНрдпрд╛рд╡рд░рдг рдКрдкрд░ рдФрд░ рдЪрд▓ рд░рд╣рд╛ рд╣реИред



fortrabbitрдирд┐рд╖реНрдХреНрд░рд┐рдп рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЛ рдЬрдорд╛ рджреЗрддрд╛ рд╣реИред рдЖрдк рдпрд╣рд╛рдВ рдХрд┐рд╕реА рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдЕрдирдлреНрд░реАрдЬ рдХрд░рдиреЗ рдХрд╛ рддрд░реАрдХрд╛ рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВ ред
рдЕрдм, рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХреЛ рднрд░рдиреЗ рдХреЗ fortrabbitрд▓рд┐рдП, рдЯрд░реНрдорд┐рдирд▓ рдкрд░ рдЬрд╛рдПрдБ:

 cd && cd workspace/php/ git clone git@git1.eu1.frbit.com:habr.git fort_habr 

fortrabbit' рд╣реЛрдЧрд╛ ' рдХреЗ рд╕рд╛рде рдЦрд╛рд▓реА рднрдВрдбрд╛рд░ рдХрд╛ рдПрдХ рдХреНрд▓реЛрди рдмрдирд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ ред рдЗрд╕рдХреЗ рдмрд╛рдж, рдмрд╕ рдкреВрд░реА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЛ рдХрд╛рд░реНрдпрдХреНрд╖реЗрддреНрд░ / php / habr рдлрд╝реЛрд▓реНрдбрд░ рд╕реЗ рдХрд╛рд░реНрдпрдХреНрд╖реЗрддреНрд░ / php / fort_habr рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░реЗрдВ ред рд╣рдо рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдЬрд╛рддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рдирдП рдбреЗрдЯрд╛ рдкрд░ рдареАрдХ рдХрд░рддреЗ рд╣реИрдВ MySQLред рдЕрдм рд╣рдо рдЕрдкрдирд╛ рдЖрд╡реЗрджрди рдЕрдкрд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИрдВ:

 cd fort_habr git add . git commit -am "Initial Commit" git push -u origin master 

рдЖрдЦрд┐рд░рдХрд╛рд░, рдпрд╣ рдорд╛рдзреНрдпрдо рд╕реЗ рдЬрд╛рдирд╛ sshрдФрд░ рдкреНрд░рд╡рд╛рд╕ рд╢реБрд░реВ рдХрд░рдирд╛ рд╣реИред рддреЛ:

 ssh u-habr@ssh1.eu1.frbit.com 

рдлрд┐рд░ рдЕрдкрдирд╛ рдкрд╛рд╕рд╡рд░реНрдб рдбрд╛рд▓реЗрдВ рдФрд░ рдЖрдк рд╕рд░реНрд╡рд░ рдкрд░ рд╣реИрдВред Htdocs
рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рдЬрд╛рдПрдВ рдФрд░ рдХрд░реЗрдВ:

 cd htdocs php artisan migrate:install php artisan migrate --seed 

рдпрджрд┐ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗрдЯрд┐рдВрдЧ рд╕рд╣реА рдереА - рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред

рдЖрдкрдХреЛ Composerрд╣реЛрд╕реНрдЯрд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рднреА рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рдирд╛ рд╣реИ ssh- рдмрд╕ рдХрдорд┐рдЯ рдореЗрдВ рдПрдХ рдЯреНрд░рд┐рдЧрд░ рдЬреЛрдбрд╝реЗрдВ:

 git commit --allow-empty -am "Update dependencies [trigger:composer:update]" git push -u origin master 

рд╡рд┐рдХрд▓реНрдк --allow-emptyрдпрд╣рд╛рдВ рд╣реИ рддрд╛рдХрд┐ рд╣рдо рдлрд╝рд╛рдЗрд▓реЛрдВ рдореЗрдВ рдХреЛрдИ рдмрджрд▓рд╛рд╡ рдХрд┐рдП рдмрд┐рдирд╛ рдХрдорд┐рдЯ рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░ рд╕рдХреЗрдВред рдПрдХ рдЦрд╛рд▓реА рдкреНрд░рддрд┐рдмрджреНрдз рдХреА рддрд░рд╣ред рд▓реЗрдХрд┐рди рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдореЗрдВ рджреЗрдЦрддреЗ рд╣реБрдП [trigger:composer:update], рд╣реЛрд╕реНрдЯрд┐рдВрдЧ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЯреАрдо рд▓реЙрдиреНрдЪ рдХрд░реЗрдЧреА composer update, рдФрд░ рд╕рднреА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдирд┐рд░реНрднрд░рддрд╛рдПрдВ рдЕрдкрдбреЗрдЯ рдХреА рдЬрд╛рдПрдВрдЧреАред

рд╡реИрд╕реЗ, GitHub рдкрд░ рдЕрдкрдиреА рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдореИрдВрдиреЗ seedsрдЫреВрдЯ рдХреЗ рд▓рд┐рдП рдЪрд┐рддреНрд░ рднреА рдЬреЛрдбрд╝реЗ ред

рдФрд░ рдЖрдЦрд┐рд░реА рдЪреАрдЬ: рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рдЖрдк рдЕрдкрдиреА рд╕рд╛рдЗрдЯ рдкрд░ рдЬрд╛рдПрдВ, рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдХрд┐ Domainsрд╕рд░реНрд╡рд░ Root PathрдореВрд▓реНрдп рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рд╣реИ publicред рдЪреВрдВрдХрд┐ рдпрд╣ рдЗрд╕ рддрд░рд╣ рд╕реЗ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рд╣реИ Laravelред

рдЖрдк рдпрд╣рд╛рдВ рдкрд░ рдЦреЗрд▓ рд╕рдХрддреЗ рд╣реИрдВ: рд╣рд╛рдмрд░рд╛ рдСрдлрд░ ред

рдирд┐рд╖реНрдХрд░реНрд╖


рдореБрдЭреЗ рдЖрд╢рд╛ рд╣реИ рдХрд┐ рдЖрдкрдХреЛ рдпрд╣ рдкрдврд╝рдиреЗ рдореЗрдВ рджрд┐рд▓рдЪрд╕реНрдк рд▓рдЧрд╛, рдФрд░ рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд╣реИред Laravel- рдЕрд▓рдЧ рдЬрдЯрд┐рд▓рддрд╛ рдХреЗ рд╡реЗрдм рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рд╡рд┐рдХрд╛рд╕ рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрддреНрдХреГрд╖реНрдЯ рд░реВрдкрд░реЗрдЦрд╛ред

рдореБрдЦреНрдп, рдФрд░ рдЗрд╕рд╕реЗ рднреА рдЕрдзрд┐рдХ рдкрд╣рд▓реБрдУрдВ, рдореИрдВрдиреЗ рд╕рдордЭрд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреАред рдФрд░ рдмреНрдпрд╛рдЬ рдХреЗ рд▓рд┐рдП рдореИрдВ рд╣реЛрдорд╡рд░реНрдХ рджреВрдВрдЧрд╛:



рд╢рд╛рдпрдж рдПрдХ рдЕрдЪреНрдЫрд╛ рдХрд╛рдо, рдХреНрдпрд╛ рдЖрдкрдХреЛ рд▓рдЧрддрд╛ рд╣реИ?

рд▓реЗрдЦрдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ



рд╕рд╛рдВрдЦреНрдпрд┐рдХреА рд╕рдВрдЧреНрд░рд╣



рдХреГрдкрдпрд╛ рд╕рднреА рд╡реНрдпрд╛рдХрд░рдг рд╕рдВрдмрдВрдзреА рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдкреАрдПрдо рдореЗрдВ рд▓рд┐рдЦреЗрдВред

рд╣реИрдЯрд░реНрд╕ рдорд░рдиреЗ рд╡рд╛рд▓реЗ рд╣реИрдВ (рдореБрдЭреЗ рдпрдХреАрди рд╣реИ рдХрд┐ рдореИрдВ рдпрд╣ рд▓рд┐рдЦреВрдВрдЧрд╛)ред

UPD : рдЙрдкрдпреЛрдЧреА рд▓рд┐рдВрдХ

Source: https://habr.com/ru/post/In197454/


All Articles