Elastic Bundle introduction

Copied from http://knpbundles.com/Exercise/FOQElasticaBundle

Elastica integration in Symfony2

Installation

Install elasticsearch

http://www.elasticsearch.org/guide/reference/setup/installation.html

Install Elastica

Download

With submodule

git submodule add git://github.com/ruflin/Elastica vendor/elastica

With clone

git clone git://github.com/ruflin/Elastica vendor/elastica

Using the vendors script

Add the following lines to your deps file:

[Elastica]
    git=git://github.com/ruflin/Elastica.git
    target=elastica

Register autoloading

// app/autoload.php

$loader->registerPrefixes(array(
    ...
    'Elastica' => __DIR__.'/../vendor/elastica/lib',
));

Install ElasticaBundle

Use the master branch with Symfony2 master only, use the 2.0 branch with Symfony2.0.x releases.

Download

With submodule

git submodule add git://github.com/Exercise/FOQElasticaBundle vendor/bundles/FOQ/ElasticaBundle

With clone

git clone git://github.com/Exercise/FOQElasticaBundle vendor/bundles/FOQ/ElasticaBundle

With the vendors script

Add the following lines to your deps file:

[FOQElasticaBundle]
    git=git://github.com/Exercise/FOQElasticaBundle.git
    target=bundles/FOQ/ElasticaBundle

For the 2.0 branch for use with Symfony2.0.x releases add the following:

[FOQElasticaBundle]
    git=git://github.com/Exercise/FOQElasticaBundle.git
    target=bundles/FOQ/ElasticaBundle
    version=origin/2.0

Run the vendors script:

$ php bin/vendors install

Register autoloading

// app/autoload.php

$loader->registerNamespaces(array(
    ...
    'FOQ' => __DIR__.'/../vendor/bundles',
));

Register the bundle

// app/AppKernel.php

public function registerBundles()
{
    return array(
        // ...
        new FOQ\ElasticaBundle\FOQElasticaBundle(),
        // ...
    );
}

Basic configuration

Declare a client

Elasticsearch client is comparable to a database connection.
Most of the time, you will need only one.

#app/config/config.yml
foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }

Declare an index

Elasticsearch index is comparable to Doctrine entity manager.
Most of the time, you will need only one.

foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default

Here we created a “website” index, that uses our “default” client.

Our index is now available as a service: foq_elastica.index.website. It is an instance of Elastica_Index.

If you need to have different index name from the service name, for example,
in order to have different indexes for different environments then you can
use the index_name key to change the index name. The service name will
remain the same across the environments:

foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            index_name: website_qa

The service id will be foq_elastica.index.website but the underlying index name is website_qa.

Declare a type

Elasticsearch type is comparable to Doctrine entity repository.

foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            types:
                user:
                    mappings:
                        username: { boost: 5 }
                        firstName: { boost: 3 }
                        lastName: { boost: 3 }
                        aboutMe: ~

Our type is now available as a service: foq_elastica.index.website.user. It is an instance of Elastica_Type.

Declaring parent field

foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            types:
                comment:
                    mappings:
                        post: {_parent: { type: "post", identifier: "id" } }
                        date: { boost: 5 }
                        content: ~

Declaring nested or object

foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            types:
                post:
                    mappings:
                        date: { boost: 5 }
                        title: { boost: 3 }
                        content: ~
                        comments:
                            type: "nested"
                            properties:
                                date: { boost: 5 }
                                content: ~

Populate the types

php app/console foq:elastica:populate

This command deletes and creates the declared indexes and types.
It applies the configured mappings to the types.

This command needs providers to insert new documents in the elasticsearch types.
There are 2 ways to create providers.
If your elasticsearch type matches a Doctrine repository or a Propel query, go for the persistence automatic provider.
Or, for complete flexibility, go for manual provider.

Persistence automatic provider

If we want to index the entities from a Doctrine repository or a Propel query,
some configuration will let ElasticaBundle do it for us.

foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            types:
                user:
                    mappings:
                        username: { boost: 5 }
                        firstName: { boost: 3 }
                        # more mappings...
                    persistence:
                        driver: orm # orm, mongodb, propel are available
                        model: Application\UserBundle\Entity\User
                        provider: ~

Three drivers are actually supported: orm, mongodb, and propel.

Use a custom Doctrine query builder

You can control which entities will be indexed by specifying a custom query builder method.

                    persistence:
                        driver: orm
                        model: Application\UserBundle\Entity\User
                        provider:
                            query_builder_method: createIsActiveQueryBuilder

Your repository must implement this method and return a Doctrine query builder.

Propel doesn’t support this feature yet.

Change the batch size

By default, ElasticaBundle will index documents by packets of 100.
You can change this value in the provider configuration.

                    persistence:
                        driver: orm
                        model: Application\UserBundle\Entity\User
                        provider:
                            batch_size: 100
Change the document identifier field

By default, ElasticaBundle will use the id field of your entities as the elasticsearch document identifier.
You can change this value in the persistence configuration.

                    persistence:
                        driver: orm
                        model: Application\UserBundle\Entity\User
                        identifier: id

Manual provider

Create a service with the tag “foq_elastica.provider” and attributes for the
index and type for which the service will provide.

    <service id="acme.search_provider.user" class="Acme\UserBundle\Search\UserProvider">
        <tag name="foq_elastica.provider" index="website" type="user" />
        <argument type="service" id="foq_elastica.index.website.user" />
    </service>

Its class must implement FOQ\ElasticaBundle\Provider\ProviderInterface.

    <?php

    namespace Acme\UserBundle\Provider;

    use FOQ\ElasticaBundle\Provider\ProviderInterface;
    use Elastica_Type;

    class UserProvider implements ProviderInterface
    {
        protected $userType;

        public function __construct(Elastica_Type $userType)
        {
            $this->userType = $userType;
        }

        /**
         * Insert the repository objects in the type index
         *
         * @param Closure $loggerClosure
         */
        public function populate(Closure $loggerClosure = null)
        {
            if ($loggerClosure) {
                $loggerClosure('Indexing users');
            }

            $document = new \Elastica_Document();
            $document->setData(array('username' => 'Bob'));
            $this->userType->addDocuments(array($document));
        }
    }

You will find a more complete implementation example in src/FOQ/ElasticaBundle/Doctrine/AbstractProvider.php.

Search

You can just use the index and type Elastica objects, provided as services, to perform searches.

/** var Elastica_Type */
$userType = $this->container->get('foq_elastica.index.website.user');

/** var Elastica_ResultSet */
$resultSet = $userType->search('bob');

Doctrine/Propel finder

If your elasticsearch type is bound to a Doctrine entity repository or a Propel query,
you can get your entities instead of Elastica results when you perform a search.
Declare that you want a Doctrine/Propel finder in your configuration:

foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            types:
                user:
                    mappings:
                        # your mappings
                    persistence:
                        driver: orm
                        model: Application\UserBundle\Entity\User
                        provider: ~
                        finder: ~

You can now use the foq_elastica.finder.website.user service:

/** var FOQ\ElasticaBundle\Finder\TransformedFinder */
$finder = $container->get('foq_elastica.finder.website.user');

/** var array of Acme\UserBundle\Entity\User */
$users = $finder->find('bob');

/** var array of Acme\UserBundle\Entity\User limited to 10 results */
$users = $finder->find('bob', 10);

You can even get paginated results!

Pagerfanta:

/** var Pagerfanta\Pagerfanta */
$userPaginator = $finder->findPaginated('bob');

Knp paginator:

$paginator = $this->get('knp_paginator');
$userPaginator = $paginator->paginate($finder->createPaginatorAdapter('bob'));

You can also get both the Elastica results and the entities together from the finder.
You can then access the score, highlights etc. from the Elastica_Result whilst
still also getting the entity.

/** var array of FOQ\ElasticaBundle\HybridResult */
$hybridResults = $finder->findHybrid('bob');
foreach ($hybridResults as $hybridResult) {

    /** var  Acme\UserBundle\Entity\User */
    $user = $hybridResult->getTransformed();

    /** var  Elastica_Result */
    $result = $hybridResult->getResult();
}
Index wide finder

You can also define a finder that will work on the entire index. Adjust your index
configuration as per below:

foq_elastica:
    indexes:
        website:
            client: default
            finder: ~

You can now use the index wide finder service foq_elastica.finder.website:

/** var FOQ\ElasticaBundle\Finder\MappedFinder */
$finder = $container->get('foq_elastica.finder.website');

// Returns a mixed array of any objects mapped
$results = $finder->find('bob');

Repositories

As well as using the finder service for a particular Doctrine/Propel entity you
can use a manager service for each driver and get a repository for an entity to search
against. This allows you to use the same service rather than the particular finder. For
example:

/** var FOQ\ElasticaBundle\Manager\RepositoryManager */
$repositoryManager = $container->get('foq_elastica.manager.orm');

/** var FOQ\ElasticaBundle\Repository */
$repository = $repositoryManager->getRepository('UserBundle:User');

/** var array of Acme\UserBundle\Entity\User */
$users = $repository->find('bob');

You can also specify the full name of the entity instead of the shortcut syntax:

/** var FOQ\ElasticaBundle\Repository */
$repository = $repositoryManager->getRepository('Application\UserBundle\Entity\User');

The 2.0 branch doesn’t support using UserBundle:User style syntax and you must use the full name of the entity. .

Default Manager

If you are only using one driver then its manager service is automatically aliased
to foq_elastica.manager. So the above example could be simplified to:

/** var FOQ\ElasticaBundle\Manager\RepositoryManager */
$repositoryManager = $container->get('foq_elastica.manager');

/** var FOQ\ElasticaBundle\Repository */
$repository = $repositoryManager->getRepository('UserBundle:User');

/** var array of Acme\UserBundle\Entity\User */
$users = $repository->find('bob');

If you use multiple drivers then you can choose which one is aliased to foq_elastica.manager
using the default_manager parameter:

foq_elastica:
    default_manager: mongodb #defauults to orm
    clients:
        default: { host: localhost, port: 9200 }
    #--
Custom Repositories

As well as the default repository you can create a custom repository for an entity and add
methods for particular searches. These need to extend FOQ\ElasticaBundle\Repository to have
access to the finder:

<?php

namespace Acme\ElasticaBundle\SearchRepository;

use FOQ\ElasticaBundle\Repository;

class UserRepository extends Repository
{
    public function findWithCustomQuery($searchText)
    {
        // build $query with Elastica objects
        $this->find($query);
    }
}

To use the custom repository specify it in the mapping for the entity:

foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            types:
                user:
                    mappings:
                        # your mappings
                    persistence:
                        driver: orm
                        model: Application\UserBundle\Entity\User
                        provider: ~
                        finder: ~
                        repository: Acme\ElasticaBundle\SearchRepository\UserRepository

Then the custom queries will be available when using the repository returned from the manager:

/** var FOQ\ElasticaBundle\Manager\RepositoryManager */
$repositoryManager = $container->get('foq_elastica.manager');

/** var FOQ\ElasticaBundle\Repository */
$repository = $repositoryManager->getRepository('UserBundle:User');

/** var array of Acme\UserBundle\Entity\User */
$users = $repository->findWithCustomQuery('bob');

Alternatively you can specify the custom repository using an annotation in the entity:

<?php

namespace Application\UserBundle\Entity;

use FOQ\ElasticaBundle\Configuration\Search;

/**
 * @Search(repositoryClass="Acme\ElasticaBundle\SearchRepository\UserRepository")
 */
class User
{

   //---

}

Realtime, selective index update

If you use the Doctrine integration, you can let ElasticaBundle update the indexes automatically
when an object is added, updated or removed. It uses Doctrine lifecycle events.
Declare that you want to update the index in real time:

foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            types:
                user:
                    mappings:
                        # your mappings
                    persistence:
                        driver: orm
                        model: Application\UserBundle\Entity\User
                        listener: # by default, listens to "insert", "update" and "delete"

Now the index is automatically updated each time the state of the bound Doctrine repository changes.
No need to repopulate the whole “user” index when a new User is created.

You can also choose to only listen for some of the events:

                    persistence:
                        listener:
                            insert: true
                            update: false
                            delete: true

Propel doesn’t support this feature yet.

Checking an entity method for listener

If you use listeners to update your index, you may need to validate your
entities before you index them (e.g. only index “public” entities). Typically,
you’ll want the listener to be consistent with the provider’s query criteria.
This may be achieved by using the is_indexable_callback config parameter:

                    persistence:
                        listener:
                            is_indexable_callback: "isPublic"

If is_indexable_callback is a string and the entity has a method with the
specified name, the listener will only index entities for which the method
returns true. Additionally, you may provide a service and method name pair:

                    persistence:
                        listener:
                            is_indexable_callback: [ "%custom_service_id%", "isIndexable" ]

In this case, the callback will be the isIndexable() method on the specified
service and the object being considered for indexing will be passed as the only
argument. This allows you to do more complex validation (e.g. ACL checks).

As you might expect, new entities will only be indexed if the callback returns
true. Additionally, modified entities will be updated or removed from the
index depending on whether the callback returns true or false, respectively.
The delete listener disregards the callback.

Propel doesn’t support this feature yet.

Advanced elasticsearch configuration

Any setting can be specified when declaring a type. For example, to enable a custom analyzer, you could write:

foq_elastica:
    indexes:
        doc:
            settings:
                index:
                    analysis:
                        analyzer:
                            my_analyzer:
                                type: custom
                                tokenizer: lowercase
                                filter   : [my_ngram]
                        filter:
                            my_ngram:
                                type: "nGram"
                                min_gram: 3
                                max_gram: 5
            types:
                blog:
                    mappings:
                        title: { boost: 8, analyzer: my_analyzer }

Overriding the Client class to suppress exceptions

By default, exceptions from the Elastica client library will propagate through
the bundle’s Client class. For instance, if the elasticsearch server is offline,
issuing a request will result in an Elastica_Exception_Client being thrown.
Depending on your needs, it may be desirable to suppress these exceptions and
allow searches to fail silently.

One way to achieve this is to override the foq_elastica.client.class service
container parameter with a custom class. In the following example, we override
the Client::request() method and return the equivalent of an empty search
response if an exception occurred.

<?php

namespace Acme\ElasticaBundle;

use FOQ\ElasticaBundle\Client as BaseClient;

class Client extends BaseClient
{
    public function request($path, $method, $data = array())
    {
        try {
            return parent::request($path, $method, $data);
        } catch (\Elastica_Exception_Abstract $e) {
            return new \Elastica_Response('{"took":0,"timed_out":false,"hits":{"total":0,"max_score":0,"hits":[]}}');
        }
    }
}

Example of Advanced Query

If you would like to perform more advanced queries, here is one example using
the snowball stemming algorithm.

It searches for Article entities using titletags, and categoryIds.
Results must match at least one specified categoryIds, and should match the
title or tags criteria. Additionally, we define a snowball analyzer to
apply to queries against the title field.

$finder = $this->container->get('foq_elastica.finder.website.article');
$boolQuery = new \Elastica_Query_Bool();

$fieldQuery = new \Elastica_Query_Text();
$fieldQuery->setFieldQuery('title', 'I am a title string');
$fieldQuery->setFieldParam('title', 'analyzer', 'my_analyzer');
$boolQuery->addShould($fieldQuery);

$tagsQuery = new \Elastica_Query_Terms();
$tagsQuery->setTerms('tags', array('tag1', 'tag2'));
$boolQuery->addShould($tagsQuery);

$categoryQuery = new \Elastica_Query_Terms();
$categoryQuery->setTerms('categoryIds', array('1', '2', '3'));
$boolQuery->addMust($categoryQuery);

$data = $finder->find($boolQuery);

Configuration:

foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        site:
            settings:
                index:
                  analysis:
                        analyzer:
                            my_analyzer:
                                type: snowball
                                language: English
            types:
                article:
                    mappings:
                        title: { boost: 10, analyzer: my_analyzer }
                        tags:
                        categoryIds:
                    persistence:
                        driver: orm
                        model: Acme\DemoBundle\Entity\Article
                        provider:
                        finder:
Advertisements

Leave a comment

mysql calendar

SELECT (CURDATE() - INTERVAL c.number DAY) AS date, 
DATE_FORMAT(CURDATE() - INTERVAL c.number DAY,'%a') as week_short,
DATE_FORMAT(CURDATE() - INTERVAL c.number DAY,'%W') as week_long,
DATE_FORMAT(CURDATE() - INTERVAL c.number DAY,'%M') as month_long,
DATE_FORMAT(CURDATE() - INTERVAL c.number DAY,'%b') as month_long,
DATE_FORMAT(CURDATE() - INTERVAL c.number DAY,'%d') as day_with_zero,
DATE_FORMAT(CURDATE() - INTERVAL c.number DAY,'%e') as day_without_zero
FROM (SELECT singles + tens + hundreds number FROM 
( SELECT 0 singles
UNION ALL SELECT   1 UNION ALL SELECT   2 UNION ALL SELECT   3
UNION ALL SELECT   4 UNION ALL SELECT   5 UNION ALL SELECT   6
UNION ALL SELECT   7 UNION ALL SELECT   8 UNION ALL SELECT   9
) singles JOIN 
(SELECT 0 tens
UNION ALL SELECT  10 UNION ALL SELECT  20 UNION ALL SELECT  30
UNION ALL SELECT  40 UNION ALL SELECT  50 UNION ALL SELECT  60
UNION ALL SELECT  70 UNION ALL SELECT  80 UNION ALL SELECT  90
) tens  JOIN 
(SELECT 0 hundreds
UNION ALL SELECT  100 UNION ALL SELECT  200 UNION ALL SELECT  300
UNION ALL SELECT  400 UNION ALL SELECT  500 UNION ALL SELECT  600
UNION ALL SELECT  700 UNION ALL SELECT  800 UNION ALL SELECT  900
) hundreds
ORDER BY number DESC) c  
WHERE c.number BETWEEN 0 and 364
;

Leave a comment

Symfony 2: Sending Email via Swiftmail

$att = \Swift_Attachment::newInstance($content, "blacklist_report_" . date("Y_m_d_H_i_s").".tsv");
$message = \Swift_Message::newInstance()
    ->setSubject('xxxxxx '.date("d/m/Y"))
    ->setFrom('no-replay@xxxx.com')
    ->setTo(array('email addresses'));
$message->attach($att);

$this->getContainer()->get('mailer')->send($message);
$mailer = $this->getContainer()->get('mailer');
$spool = $mailer->getTransport()->getSpool();
$transport = $this->getContainer()->get('swiftmailer.transport.real');
$spool->flushQueue($transport);

Leave a comment

Symfony – how it loading bundle extension

Symfony\Component\HttpKernel\Kernal

public function prepareContainer;  look at following one line;

$container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions));
MergeExtensionConfigurationPass been added to pass config.

then in
Symfony\Component\HttpKernel\Kernal's protected function initializeContainer()
$container->compile(); this method will call
MergeExtensionConfigurationPass's process method.

in the process method,
$extension->load($config, $tmpContainer);
will call registered extension's load method.

Leave a comment

Magento class naming

so in my config file, i have following :

Anru_NZRegion_Helper

pay attention to “Anru_NZRegion_Helper”, “NZR” 3 letters are upper case.

in helpers’ Data file, i have Anru_NZRegion_Helper_Data class. and Magento complains about no class found.

This is because of Magento tried to explode “Anru_NZRegion_Helper” into 3 different parts, then join those parts back, and upper casing each part’s first letter, so class name becomes
“Anru_Nzregion_Helper”.

Also, Magento use Anru_NZRegion as a folder name to auto – include class.

there was a bug wasted so many of mine time, because In my home computer , my Mangento is installed on a vagrant machine, and on a shared folder, and my host machine is windows, which means folder name is case – insensitive. but Linux is case-sensitive.

initially, I had this Anru_Nzregion_Helper , in linux it becomes “Anru/Nzregion” folder name
and worked on my local machine but failed on my linux host.

Leave a comment

Symfony to generate dynamic routing

For dynamic routing, one of problem is Symphony looking for router

from cache file, and dynamic router is not saved into cache, for deal with this problem,

we have to delete Symphony’s router cache file. here is how to do it.

1> we have to build up a service. define service file first

example.cache:
    class: Example\CacheBundle\Service\RouterCacheService
    arguments:
      - @router
      - %kernel.environment%
      - %kernel.cache_dir%

use Symfony\Component\Routing\Router;

class RouterCacheService
{
    private $router;
    private $environment;
    private $cache_dir;
    public function __construct(Router $router, $env, $cacheDir)
    {
        $this->router = $router;
        $this->environment = $env;
        $this->cache_dir = $cacheDir;
    }
    public function clearCache($environment = null)
    {
        if (null === $environment) {
            $environment = $this->environment;
        }

        $this->router->clearCache($this->cache_dir, $environment, $this->environment == $environment);
    }
}

2> overriding cache clean function. In Symphony , there is a
Symfony\Bundle\FrameworkBundle\Routing\Router class, we need to extends this class, and overriding clearCache method. here is code: under bundler’s Routing folder, create this class,
use Symfony\Bundle\FrameworkBundle\Routing\Router as BaseRouter;

class CacheCleanRouter extends BaseRouter
{
    public function clearCache($cache_dir, $environment, $warm_up)
    {
        $environment = ucfirst($environment);

        @unlink($cache_dir .'/app'. $environment .'UrlMatcher.php');
        @unlink($cache_dir .'/app'. $environment .'UrlGenerator.php');

        if ($warm_up) {
            $this->matcher   = null;
            $this->generator = null;
            $this->warmUp($cache_dir);
        }
    }
}

 

So now , we are able to clean our cache, this will make Dynamic URL correctly recognized by Symfony framework.

the next step we have to do is to write class to generate dynamic URL.

Symfony official doc, https://symfony.com/doc/current/routing/custom_route_loader.html

Pay attention to load method,and $routesContainer. under bundler’s Routing folder, create this class,

class RoutesLoader implements LoaderInterface
{
    /**
     * @var EntityManagerInterface
     */
    protected $entityManager;

    /**
     * @var RoutesContainer
     */
    protected $routesContainer;

    public function __construct(EntityManagerInterface $entityManager, RoutesContainer $routesContainer)
    {
        $this->entityManager = $entityManager;
        $this->routesContainer = $routesContainer;
    }

    /**
     * {@inheritdoc}
     */
    public function load($resource, $type = null)
    {
        $examples = $this->entityManager->getRepository('MyExampleBundle:Examples')->findAll();
        $routes = new RouteCollection();

        foreach ($examples as $example) {
            $custom = $this->routesContainer->getCustomRoutes($example->getSlug());

            foreach ($custom as $name => $route) {
                $routes->add($name, $route);
            }
        }

        return $routes;
    }

    /**
     * {@inheritdoc}
     */
    public function supports($resource, $type = null)
    {
        return 'my_example' === $type;
    }

    /**
     * {@inheritdoc}
     */
    public function getResolver()
    {
        //
    }

    /**
     * {@inheritdoc}
     */
    public function setResolver(LoaderResolverInterface $resolver)
    {
        //
    }
}

 

after defined RoutesLoader class, we need to set it up as a service

myexample.loader.routes_loader:
    class: myexample\Routing\RoutesLoader
    arguments:
        - @doctrine.orm.entity_manager
        - @myexample.routing.routes_container
    tags:
        - { name: routing.loader }
now, it time to define a class to generate dynamic url. create the class as a service first,
myexample.routing.routes_container:
    class: myexample\Routing\RoutesContainer
    arguments:
        - @router

under bundler’s Routing folder, create this class, define a examples.list string which represents /{anytext}-example router.

class RoutesContainer
{
    protected $router;
    protected $config = [
'examples.list'                    => [
            'pattern'  => '/%prefix%-example',
            'nested'   => true,
            'methods'  => [
                'GET',
            ],
            'defaults' => [
                '_controller' => 'myexample:Examples:list',
            ],
       ],
       'examples.edit'                    => [
            'pattern'  => '/%prefix%-example/{id}/edit',
            'nested'   => true,
            'methods'  => [
                'GET',
            ],
           'defaults' => [
              '_controller' => 'myexample:Examples:edit',
           ],
      ],
 ];

protected $routesPrefix = 'myexamples.';

public function __construct(RouterInterface $router)
{
    $this->router = $router;
}

public function getCustomRoutes($prefix)
{
    $routes = [];

    foreach ($this->config as $name => $params) {
        list($name, $route) = $this->createRoute($name, $prefix);
        $routes[$name] = $route;
    }

    return $routes;
}

public function getRealRouteName($routeName, $prefix)
{
    if (!isset($this->config[$routeName])) {
        throw new RouteNotFoundException(sprintf('Route %s not found', $routeName));
    }
    $config = $this->config[$routeName];
    $name = implode('.', [$prefix, $routeName]);

    if ($config['nested']) {
        $name = $this->routesPrefix.$name;
    }

    return $name;
}

/** TODO: this should be more explicit */
public function getPrefixFromRoute($name)
{
    $name = str_replace($this->routesPrefix, '', $name);

    return substr($name, 0, strpos($name, '.'));
}

public function checkAvailability($pattern)
{
    $routes = $this->router->getRouteCollection()->all();

    foreach ($routes as $route) {
        if ($route->getPath() === $pattern) {
            return false;
        }
    }

    return true;
}

public function generateRoute($name, $prefix, array $params = [], $absolute = RouterInterface::ABSOLUTE_PATH)
{
    return $this->router->generate($this->getRealRouteName($name, $prefix), $params, $absolute);
}

protected function createRoute($name, $prefix)
{
    $config = $this->config[$name];
    $name = $this->getRealRouteName($name, $prefix);

    $route = new Route(str_replace('%prefix%', $prefix, $config['pattern']), $config['defaults']);
    $route->setMethods($config['methods']);

    return [$name, $route];
}

}

 

now all code is here, but how we going to use it? says, you want to know what is route name for ‘examples.list’ in your controller.

$prefix = 'pen';

$this->get('myexample.routing.routes_container')->getRealRouteName('examples.list', $prefix);

the above code will find out router for pen-example
want redirect to dynamic url in your controller?
$prefix = 'pen';
$id = 2;
$url = $this->get('myexample.routing.routes_container')->getRealRouteName('examples.edit', $prefix);
$this->redirectToRoute(
    $url
    [
     'id' => $id,
    ]
);

			

Leave a comment

signing a powershell script

code signing need to executed in administrator context

0> write a powershell script hello.ps1
1> Set-ExecutionPolicy AllSigned

generates a self signed certificate
2> New-SelfSignedCertificate -DnsName powershell-self-sign -Type CodeSigning

signing a script

3> Set-AuthenticodeSignature C:\t\hello.ps1 @(gci Cert:\LocalMachine\My -DnsName powershell-self-sign -codesigning)[0]

4> run cert from start menu.
5> from Personal/Certificate, find powershell-self-sign cert
6> right click the cert , and copy , then paste the cert to intermediate certificate authoritties/Certificates
7> paste the cert to Trusted Root / certificate.

Leave a comment