Setting up CircleCI Continuous Integration with Laravel – Then deploy Forge or Fortrabbit

Including Continuous Integration is great, but there are many providers to choose from. CircleCI has a pretty decent free plan, but using it for your Laravel app might be a bit confusing.

Instructions for deploying Laravel 5.5 with Circle CI:

This site has a nice boilerplate script:

https://medium.com/@wesmahler/circleci-2-0-configuration-for-laravel-5-5-with-laravel-dusk-ab1cc9b9d4a7

But if you found a better script, let us know in the comments.

Make sure you have specified the testing environment variables in your .env.testing and phpunit.xml if you are using PHPUnit.

Getting a Mysql Root error?

Since March 2021, we sometimes got this error:

[ERROR] [Entrypoint]: MYSQL_USER="root", MYSQL_PASSWORD cannot be used for the root user
    Use one of the following to control the root user password:
    - MYSQL_ROOT_PASSWORD
    - MYSQL_ALLOW_EMPTY_PASSWORD
    - MYSQL_RANDOM_ROOT_PASSWORD

We solved it by changing the MYSQL_USER to another name than ‘root’.

Deploying on Laravel Forge via CI

After that call this forge-deploy.sh script in your final step in config.yml:

  - run:
     name: Run deploy script
     command: sudo chmod +x ./deploy.sh; sudo ./deploy.sh

Then create a deploy.sh script in your app and include the Laravel Forge / Envoyer deployment trigger URL (can be found in your app’s dashboard in Laravel Forge / Envoyer):

#!/bin/bash
# Trigger deployment
# Replace the url below with your envoyer/forge url
# APPLICATION1
curl -s 'https://forge.laravel.com/servers/123456...';

# APPLICATION2 - if you have multiple applications that needs to be deployed and triggered
curl -s 'https://forge.laravel.com/servers/12345678...';

echo 'Deployment triggered!'

After this, you can push to Github or Bitbucket and see if the build succeeds and deploys to Laravel Forge / Envoyer. Make sure you disable auto-deploy, as you only would like to deploy to Laravel Forge / Envoyer after a successful CI build.

Deploy on Fortrabbit with CircleCI

Rather want to deploy on Fortrabbit instead of Laravel Forge after a successful CircleCI build?

Read more about using CI with Fortrabbit here.

To setup the deployment to Fortrabbit from CircleCI follow this procedure:

  1. Run this script on a terminal client: ssh-keygen -m PEM -t rsa -C “your_email@example.com”
  2. Copy the private key to CircleCI
  3. Go to the project -> SSH Keys -> Additional SSH Keys Enter hostname: deploy.XYZ.frbit.com (replace XYX with your Fortrabbit server location)
  4. Add the public key in the Fortrabbit Dashboard’s public SSH key manager
  5. Add the fingerprint that you see in the CircleCI dashboard to the config.yml file:
  6. NOTE: adding a SSH key to a third party service always carries out risks, be aware of them and if it’s too risky, don’t take these steps.
version: 2
jobs:
  deploy-job:
    steps:
      - add_ssh_keys:
          fingerprints:
            - "SO:ME:FIN:G:ER:PR:IN:T"

Try to push the updated files to Github or Bitbucket.

See whether this build succeeds. If not, fix the issues until it works.

Add this code to the circleci/config.yml script after the testing steps:

      - run:
         name: Add FRBIT remote
         command: git remote add frbit YOURFRBITGITURL

      - run:
         name: Add FRBIT remote fingerprint to known hosts
         command: ssh-keyscan deploy.XYZ.frbit.com >> ~/.ssh/known_hosts

      - run:
         name: Deploy to FRBIT
         command: git push frbit

Don’t forget to replace the variables YOURFRBITGITURL and XYZ.

Using these scripts and instructions is on your own risk of course.

Got any suggestions for a better workflow? Let us know!

Laravel Add List-Unsubscribe Header to Mail (e.g. Mailgun & Hotmail)

When using e.g. Mailgun for Laravel Mail, sometimes it could happen that mails end up in spamfolders. One of the reasons for this is that default a List-Unsubscribe header is not set. That is a link that you send to your unsubscribe mail.

Add this code in you mail closure:

$message->getSwiftMessage()
                    ->getHeaders()
                    ->addTextHeader('List-Unsubscribe', '<' . action('NewsletterController@delete', 'YOURUSERIDORTOKEN') . '>');

So then it becomes like:

\Mail::send(['emails.newsletter-activate.html', 'emails.newsletter-activate.text'], $toMailView, function ($message) use ($email, $subject) {
            $message->subject($subject);
            $message->to($email);
            $message->getSwiftMessage()
                    ->getHeaders()
                    ->addTextHeader('List-Unsubscribe', '<' . action('NewsletterController@delete', 'YOURUSERIDORTOKEN') . '>');
        });

This seems to work in Hotmail. In our cases it removed the case where Hotmail moved our Mailgun e-mails to the SPAM-box.

Are mails completely blocked by your ISP? Ask MailGun for a new IP

We also had a case where Mailgun assigned us an IP that was blocked by Hotmail. Send a support query to Mailgun and ask for a new IP-address. With above tips Mailgun delivered our e-mails correctly in the mailbox.

Validating meta title and meta description with jQuery

Would you like to auto-display validation hints when a meta_title field is longer than 55 chars and a meta_description field is longer than 155 chars?

Then you can use this package: jQuery Meta Title and Description Validation.

Setup
1. Have at least one input field named meta_title or meta_description

E.g.

2. Initialize by including jquery-meta-validation.js


Laravel 5 Admin Middleware (is_admin user check)

Would you like to have middleware that makes sure that only users with an is_admin = 1 status will be able to see the admin section? Then you can use the following code:

app/Http/Middleware/AdminMiddleware.php

is_admin == 1)
        {
            return $next($request);
        }

        return redirect()->guest('/');
    }
}

Make sure you’ll register the middleware as a route in app/Http/Kernel.php

protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'admin' => \App\Http\Middleware\AdminMiddleware::class
];

Finally assign this middleware in the routes.php next to the auth middleware, since the admin middleware is an extension to the auth middleware.

App/Http/routes.php

Route::group(['prefix' => 'administration', 'middleware' => ['auth', 'admin']], function()
{
	Route::get('/', 'Admin\HomeController@index');
}

If you’ve suggestions to make this coding more efficient, you’re always welcome to drop a comment below.

SSH import sql database with host syntax (if not localhost)

How to import a .sql.gz file when the host is not localhost? Use this syntax:

$ mysql -h db365838511.db.1and1.com -u dbun1234 -p db365838511 < 1and1help.com-Joomla-Apr.05.2010.sql

Explanation:

  • mysql: This is the MySQL command to access your databases
  • -h db365838511.db.1and1.com: This is the Host Name where your database is located (available from the 1&1 Control Panel).
  • -u dbun1234: This is the User Name for your database (available from the 1&1 Control Panel).
  • -p: This is to prompt for a password. Do not type the password now. You will be asked for the password after you hit ENTER.
  • db111111111: This is the database name.
  • < : This is to specify a database file should be imported to the database.
  • 1and1help.com-Joomla-Apr.05.2010.sql: This is the filename you will enter to specify which of the files you wish to import.

Source: 1and1

Magento Show Poll Results

Add this code in order to show the poll results in de poll block (using this article):

In addition for the result add in poll.phtml:

if ($poll->isVoted($poll->getId()) == TRUE) {
//Template Block
echo $this->getLayout()->createBlock(‘core/template’)->setTemplate(‘poll/result.phtml’)->setAttribute(‘my_poll_id’, $poll->getId())->toHtml();
} else {

// add the rest of the poll script here

}

Further open results.phtml and add on top:

if(!isset($poll)) {
$poll = new Mage_Poll_Model_Poll();
$poll->load($this->my_poll_id);

$action = Mage::getUrl(‘poll/vote/add’, array(‘poll_id’ => $poll->getId()));

$poll_answers = Mage::getModel(‘poll/poll_answer’)
->getResourceCollection()
->addPollFilter($poll->getId())
->load()
->countPercent($poll);

}

This should do the trick!

Lesti::Fpc and Layered Navigation

Lesti::Fpc is a great free Full Page Cache plugin for Magento. Though, it could be that it doesn’t work with Layered Navigation.

Solution

1. Go to your site and layered navigation and hover with your mouse on a filter item. It shows the url parameters (like ?color=red&manufacturer=brand).

2. Those parameter you need to add in the admin > config > system > Lesti::FPC > URL params. There add all the possible parameters from above. Like:

price,
cat,
manufacturer,
no_cache,
color

 

Magento import multiple images in dataflow csv/xml

Sometimes it’s really annoying that Magento only supports one image per product. On the Magento Commerce forum a solution is found:

Now, what you need to do is open the file
app/code/core/Mage/Catalog/Model/Convert/Adapter/Product.php
and go to around line 773 and find

$addedFilesCorrespondence = $mediaGalleryBackendModel->addImagesWithDifferentMediaAttributes(
$product,
$arrayToMassAdd, Mage::getBaseDir('media') . DS . 'import',
false,
false
);

and paste the following code right after it
if (isset($importData['media_gallery']) && !empty($importData['media_gallery'])) {
$x = explode(',', $importData['media_gallery']);
foreach ($x as $file) {
$imagesToAdd[] = array('file' => trim($file));
}
$mediaGalleryBackendModel->addImagesWithDifferentMediaAttributes(
$product,
$imagesToAdd, Mage::getBaseDir('media') . DS . 'import',
false,
false
);
}

Source: http://www.magentocommerce.com/boards/viewthread/224928/P45/

Magento place order slow [FIXED]

The Magento “place order” step can take up to a minute. With thanks to this site I figured out how to fix slow checkouts.

Step 1

Find the file app/code/core/Mage/Rss/etc/config.xml and uncomment/remove:

<sales_order_save_after>
<observers>
<notifystock>
<class>rss/observer</class>
<method>salesOrderItemSaveAfterNotifyStock</method>
</notifystock>
</observers>
</sales_order_save_after>
<sales_order_save_after>
<observers>
<ordernew>
<class>rss/observer</class>
<method>salesOrderItemSaveAfterOrderNew</method>
</ordernew>
</observers>
</sales_order_save_after>

Step 2

Find the file app/code/core/Mage/Downloadable/etc/config.xml and uncomment/remove:

<!–sales_order_item_save_commit_after>
<observers>
<downloadable_observer>
<class>downloadable/observer</class>
<method>saveDownloadableOrderItem</method>
</downloadable_observer>
</observers>
</sales_order_item_save_commit_after–>