9

Here is my Magento code:

private function getAllCountry() {

    require_once("../app/Mage.php");
    umask(0);
    Mage::app("default");

    $countryName = Mage::getModel('directory/country')->load('FR')->getName(); //get country name

    echo 'Country Name ->'.$countryName.'<br/>';

    $states = Mage::getModel('directory/country')->load('FR')->getRegions();//state names

    foreach ($states as $state)
    {
        echo 'ID->'.$state->getId().'<br/>';
        echo 'Name->'.$state->getName().'<br/>';

    }
}

I want to get the list of all country names with their states and region id in an array.

0

3 Answers 3

14

Note that although these answers might work, they're not the proper Magento Way™ to do this. The right path to choose is to use Service Contract.

The Directory module comes with a very handy Service Contract called the "CountryInformationAcquirerInterface". You can find it at Magento\Directory\Api\CountryInformationAcquirerInterface. This has a very handy function called getCountriesInfo(), which returns an array of CountryInformation data models, which - in their turn - have a method called getAvailableRegions(). So the full example would look something like this:

/**
 * @var \Magento\Directory\Api\CountryInformationAcquirerInterface
 */
protected $countryInformationAcquirer;

/**
 * Constructor call.
 * @param \Magento\Directory\Api\CountryInformationAcquirerInterface $countryInformationAcquirer
 */
public function __construct(
    \Magento\Directory\Api\CountryInformationAcquirerInterface $countryInformationAcquirer
) {
    $this->countryInformationAcquirer = $countryInformationAcquirer;
}

/**
 * Just a simple example
 * @return array
 */
public function example()
{
    $data = [];

    $countries = $this->countryInformationAcquirer->getCountriesInfo();

    foreach ($countries as $country) {
        // Get regions for this country:
        $regions = [];

        if ($availableRegions = $country->getAvailableRegions()) {
            foreach ($availableRegions as $region) {
                $regions[] = [
                    'id'   => $region->getId(),
                    'code' => $region->getCode(),
                    'name' => $region->getName()
                ];
            }
        }

        // Add to data:
        $data[] = [
            'value'   => $country->getTwoLetterAbbreviation(),
            'label'   => __($country->getFullNameLocale()),
            'regions' => $regions
        ];
    }

    return $data;
}

With most tasks in Magento 2, the best approach is to check first if there's a Service Contract that might fit your needs. Because most of the time, there is.

3
  • Are there any "restriction" not to use API/Service Contracts?
    – sv3n
    Oct 11, 2018 at 23:15
  • 1
    Not as far as I'm aware of. It's even more reliable: if the service contract has an @api-annotation, it's guaranteed to be backward compatible (see devdocs.magento.com/guides/v2.2/extension-dev-guide/… and devdocs.magento.com/guides/v2.2/contributor-guide/…). The only "restriction" I can think of is DI: since you depend on abstractions you don't know the explicit implementation. But then again: the whole idea of interfaces is that you should not need to care about this. If you do care about this, you probably have a code smell. Oct 15, 2018 at 8:38
  • I like this, but it only returns the countries enabled for the current store (which normally would be fine), but in this case I'd like every country. Is there a way to do that with this Service Contract?
    – wr125
    Feb 11, 2020 at 12:04
9

Try this for Magento2. It will return an multi array with country's and there regions if available.

$countryHelper = $this->_objectManager->get('Magento\Directory\Model\Config\Source\Country'); 
$countryFactory = $this->_objectManager->get('Magento\Directory\Model\CountryFactory');

$countries = $countryHelper->toOptionArray(); //Load an array of countries

    foreach ( $countries as $countryKey => $country ) {

        if ( $country['value'] != '' ) { //Ignore the first (empty) value

            $stateArray = $countryFactory->create()->setId(
                $country['value']
            )->getLoadedRegionCollection()->toOptionArray(); //Get all regions for the given ISO country code

            if ( count($stateArray) > 0 ) { //Again ignore empty values
                $countries[$countryKey]['states'] = $stateArray;
            }

        }
    }

var_dump($countries);

STAND ALONE VERSION

Add the code below to a file 'test.php' in your magento root directory and navigate to it from a web browser. By no means should you attempt to use objectmanager directly inside of a controller, but outside of magento, this is the 'approved' way of getting to it.

<?php


use Magento\Framework\AppInterface;

try {
    require __DIR__ . '/app/bootstrap.php';

} catch (\Exception $e) {
    echo 'Autoload error: ' . $e->getMessage();
    exit(1);
}
try {
    $bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);
    $objectManager = $bootstrap->getObjectManager();

    $countryHelper = $objectManager->get('Magento\Directory\Model\Config\Source\Country');
    $countryFactory = $objectManager->get('Magento\Directory\Model\CountryFactory');
    $countryCollection = $objectManager->get('Magento\Directory\Model\ResourceModel\Country\Collection');

$items = $countryCollection->loadByStore(null);

foreach ($items as $item) {
    var_dump($item->getData());
}

$countries = $countryHelper->toOptionArray(); //Load an array of countries
foreach ( $countries as $countryKey => $country ) {


if ( $country['value'] != '' ) { //Ignore the first (empty) value

            $stateArray = $countryFactory->create()->setId(
                $country['value']
            )->getLoadedRegionCollection()->toOptionArray(); //Get all regions for the given ISO country code

            if ( count($stateArray) > 0 ) { //Again ignore empty values
                $countries[$countryKey]['states'] = $stateArray;
            }

        }
    }
4
  • Please update your answer with an explanation of what the code does and how it will solve the OP's problem.
    – 7ochem
    Mar 18, 2016 at 11:04
  • This code works perfectly. I suppose its a prerequisite you need to understand magento dependency injection in order to get it to work. It returns an array of the countries, and regions.
    – CarComp
    Jun 3, 2016 at 18:01
  • +1 for Good work...! Keep it up..! May 21, 2019 at 18:46
  • Where is the state man! Oct 29, 2020 at 14:59
3

Done in two files:

Template File:

<select name="countries">
    <option class="placeholder" value="" disabled selected>Country</option>
    <?php 
        $countries = $block->getAvailableCountries();
        foreach ($countries as $country) { ?>
            <option value="<?php echo $country->getCountryId(); ?>"><?php echo $country->getName(); ?></option>
        }
    ?>
</select>

Block File:

use Magento\Directory\Model\ResourceModel\Country\CollectionFactory as CountryCollectionFactory;
use Magento\Framework\View\Element\Template;

class Catalogue extends Template
{

    protected $_countryCollectionFactory;

    public function __construct(
        CountryCollectionFactory $countryCollectionFactory,
        Template\Context $context,
        array $data = []
    )
    {
        $this->_countryCollectionFactory = $countryCollectionFactory;
        parent::__construct($context, $data);
    }

    public function getAvailableCountries()
    {
        $collection = $this->_countryCollectionFactory->create();
        $collection->addFieldToSelect('*');

        return $collection;
    }

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.