<commit_before><?php
/**
 * @package     Mautic
 * @copyright   2014 Mautic Contributors. All rights reserved.
 * @author      Mautic
 * @link        http://mautic.org
 * @license     GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */

namespace Mautic\PageBundle\Model;

use Mautic\CoreBundle\Helper\InputHelper;
use Mautic\CoreBundle\Model\FormModel;
use Mautic\PageBundle\Entity\Hit;
use Mautic\PageBundle\Entity\Page;
use Mautic\PageBundle\Entity\Redirect;
use Mautic\PageBundle\Event\PageBuilderEvent;
use Mautic\PageBundle\Event\PageEvent;
use Mautic\PageBundle\Event\PageHitEvent;
use Mautic\PageBundle\PageEvents;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;

/**
 * Class PageModel
 */
class PageModel extends FormModel
{

    /**
     * @return \Mautic\PageBundle\Entity\PageRepository
     */
    public function getRepository ()
    {
        $repo = $this->em->getRepository('MauticPageBundle:Page');
        $repo->setCurrentUser(
            $this->factory->getUser()
        );
        return $repo;
    }

    /**
     * @return \Mautic\PageBundle\Entity\HitRepository
     */
    public function getHitRepository()
    {
        return $this->em->getRepository('MauticPageBundle:Hit');
    }

    /**
     * {@inheritdoc}
     */
    public function getPermissionBase ()
    {
        return 'page:pages';
    }

    /**
     * {@inheritdoc}
     */
    public function getNameGetter ()
    {
        return 'getTitle';
    }

    /**
     * {@inheritdoc}
     *
     * @param Page $entity
     * @param bool $unlock
     */
    public function saveEntity ($entity, $unlock = true)
    {
        if (empty($this->inConversion)) {
            $alias = $entity->getAlias();
            if (empty($alias)) {
                $alias = strtolower(InputHelper::alphanum($entity->getTitle(), false, '-'));
            } else {
                $alias = strtolower(InputHelper::alphanum($alias, false, '-'));
            }

            //make sure alias is not already taken
            $repo      = $this->getRepository();
            $testAlias = $alias;
            $count     = $repo->checkUniqueAlias($testAlias, $entity);
            $aliasTag  = $count;

            while ($count) {
                $testAlias = $alias . $aliasTag;
                $count     = $repo->checkUniqueAlias($testAlias, $entity);
                $aliasTag++;
            }
            if ($testAlias != $alias) {
                $alias = $testAlias;
            }
            $entity->setAlias($alias);
        }

        $now = new \DateTime();

        //set the author for new pages
        if (!$entity->isNew()) {
            //increase the revision
            $revision = $entity->getRevision();
            $revision++;
            $entity->setRevision($revision);

            //reset the variant hit and start date if there are any changes
            $changes   = $entity->getChanges();
            $isVariant = $entity->getVariantStartDate();
            if ($isVariant !== null && !empty($changes) && empty($this->inConversion)) {
                $entity->setVariantHits(0);
                $entity->setVariantStartDate($now);
            }
        }

        parent::saveEntity($entity, $unlock);

        //also reset variants if applicable due to changes
        if (!empty($changes) && empty($this->inConversion)) {
            $parent   = $entity->getVariantParent();
            $children = (!empty($parent)) ? $parent->getVariantChildren() : $entity->getVariantChildren();

            $variants = array();
            if (!empty($parent)) {
                $parent->setVariantHits(0);
                $parent->setVariantStartDate($now);
                $variants[] = $parent;
            }

            if (count($children)) {
                foreach ($children as $child) {
                    $child->setVariantHits(0);
                    $child->setVariantStartDate($now);
                    $variants[] = $child;
                }
            }

            //if the parent was changed, then that parent/children must also be reset
            if (isset($changes['variantParent'])) {
                $parent = $this->getEntity($changes['variantParent'][0]);
                if (!empty($parent)) {
                    $parent->setVariantHits(0);
                    $parent->setVariantStartDate($now);
                    $variants[] = $parent;

                    $children = $parent->getVariantChildren();
                    if (count($children)) {
                        foreach ($children as $child) {
                            $child->setVariantHits(0);
                            $child->setVariantStartDate($now);
                            $variants[] = $child;
                        }
                    }
                }
            }

            if (!empty($variants)) {
                $this->saveEntities($variants, false);
            }
        }
    }

    /**
     * {@inheritdoc}
     *
     * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
     */
    public function createForm ($entity, $formFactory, $action = null, $options = array())
    {
        if (!$entity instanceof Page) {
            throw new MethodNotAllowedHttpException(array('Page'));
        }

        if (!isset($options['formName'])) {
            $options['formName'] = 'page';
        }

        $params = (!empty($action)) ? array('action' => $action) : array();

        return $formFactory->create($options['formName'], $entity, $params);
    }

    /**
     * {@inheritdoc}
     *
     * @return null|Page
     */
    public function getEntity ($id = null)
    {
        if ($id === null) {
            $entity = new Page();
            $entity->setSessionId('new_' . hash('sha1', uniqid(mt_rand())));
        } else {
            $entity = parent::getEntity($id);
            if ($entity !== null) {
                $entity->setSessionId($entity->getId());
            }
        }

        return $entity;
    }

    /**
     * {@inheritdoc}
     *
     * @throws \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException
     */
    protected function dispatchEvent ($action, &$entity, $isNew = false, Event $event = null)
    {
        if (!$entity instanceof Page) {
            throw new MethodNotAllowedHttpException(array('Page'));
        }

        switch ($action) {
            case 'pre_save':
                $name = PageEvents::PAGE_PRE_SAVE;
                break;
            case 'post_save':
                $name = PageEvents::PAGE_POST_SAVE;
                break;
            case 'pre_delete':
                $name = PageEvents::PAGE_PRE_DELETE;
                break;
            case 'post_delete':
                $name = PageEvents::PAGE_POST_DELETE;
                break;
            default:
                return null;
        }

        if ($this->dispatcher->hasListeners($name)) {
            if (empty($event)) {
                $event = new PageEvent($entity, $isNew);
                $event->setEntityManager($this->em);
            }

            $this->dispatcher->dispatch($name, $event);

            return $event;
        }

        return null;
    }

    /**
     * Get list of entities for autopopulate fields
     *
     * @param string $type
     * @param string $filter
     * @param int    $limit
     *
     * @return array
     */
    public function getLookupResults ($type, $filter = '', $limit = 10)
    {
        $results = array();
        switch ($type) {
            case 'page':
                $viewOther = $this->security->isGranted('page:pages:viewother');
                $repo      = $this->getRepository();
                $repo->setCurrentUser($this->factory->getUser());
                $results = $repo->getPageList($filter, $limit, 0, $viewOther);
                break;
        }

        return $results;
    }

    /**
     * Generate URL for a page
     *
     * @param Page  $entity
     * @param bool  $absolute
     * @param array $clickthrough
     *
     * @return string
     */
    public function generateUrl ($entity, $absolute = true, $clickthrough = array())
    {
        // If this is a variant, then get the parent's URL
        $parent = $entity->getVariantParent();
        if ($parent != null) {
            $entity = $parent;
        }

        $slug = $this->generateSlug($entity);

        return $this->buildUrl('mautic_page_public', array('slug' => $slug), $absolute, $clickthrough);
    }

    /**
     * Generates slug string
     *
     * @param $entity
     *
     * @return string
     */
    public function generateSlug ($entity)
    {
        $pageSlug =  $entity->getAlias();

        //should the url include the category
        $catInUrl = $this->factory->getParameter('cat_in_page_url');
        if ($catInUrl) {
            $category = $entity->getCategory();
            $catSlug  = (!empty($category)) ? $category->getAlias() :
                $this->translator->trans('mautic.core.url.uncategorized');
        }

        $parent = $entity->getTranslationParent();
        $slugs  = array();
        if ($parent) {
            //multiple languages so tack on the language
            $slugs[] = $entity->getLanguage();
        }

        if (!empty($catSlug)) {
            // Insert category slug
            $slugs[] = $catSlug;
            $slugs[] = $pageSlug;
        } else {
            // Insert just the page slug
            $slugs[] = $pageSlug;
        }

        return implode('/', $slugs);
    }

    /**
     * @param Page    $page
     * @param Request $request
     * @param string  $code
     *
     * @return void
     */
    public function hitPage ($page, $request, $code = '200')
    {
        //don't skew results with in-house hits
        if (!$this->factory->getSecurity()->isAnonymous()) {
            return;
        }

        $hitRepo = $this->getHitRepository();
        $hit = new Hit();
        $hit->setDateHit(new \Datetime());

        //check for existing IP
        $ipAddress = $this->factory->getIpAddress();
        $hit->setIpAddress($ipAddress);

        /** @var \Mautic\LeadBundle\Model\LeadModel $leadModel */
        $leadModel = $this->factory->getModel('lead');

        //check for any clickthrough info
        $clickthrough = $request->get('ct', false);
        if (!empty($clickthrough)) {
            $clickthrough = $this->decodeArrayFromUrl($clickthrough);

            if (!empty($clickthrough['lead'])) {
                $lead = $leadModel->getEntity($clickthrough['lead']);
                if ($lead !== null) {
                    $leadModel->setLeadCookie($clickthrough['lead']);
                    $leadClickthrough = true;

                    $leadModel->setCurrentLead($lead);
                }
            }

            if (!empty($clickthrough['source'])) {
                $hit->setSource($clickthrough['source'][0]);
                $hit->setSourceId($clickthrough['source'][1]);
            }

            if (!empty($clickthrough['email'])) {
                $hit->setEmail($this->em->getReference('MauticEmailBundle:Email', $clickthrough['email']));
            }
        }

        if (empty($leadClickthrough)) {
            $lead = $leadModel->getCurrentLead();
        }

        if ($page instanceof Redirect) {
            //use the configured redirect URL
            $pageURL = $page->getUrl();
        } else {
            //use current URL

            // Tracking pixel is used
            if (strpos($request->server->get('REQUEST_URI'), '/mtracking.gif') !== false) {
                $pageURL = $request->server->get('HTTP_REFERER');

                // if additional data were sent with the tracking pixel
                if ($request->server->get('QUERY_STRING')) {
                    parse_str($request->server->get('QUERY_STRING'), $query);

                    // URL attr 'd' is encoded so let's decode it first.

                    $decoded = false;
                    if (isset($query['d'])) {
                        // parse_str auto urldecodes
                        $query   = unserialize(base64_decode($query['d']));
                        $decoded = true;
                    }

                    if (isset($query['url'])) {
                        $pageURL = $query['url'];
                        if (!$decoded) {
                            $pageURL = urldecode($pageURL);
                        }
                    }

                    if (isset($query['referrer'])) {
                        if (!$decoded) {
                            $query['referrer'] = urldecode($query['referrer']);
                        }
                        $hit->setReferer($query['referrer']);
                    }

                    if (isset($query['language'])) {
                        if (!$decoded) {
                            $query['language'] = urldecode($query['language']);
                        }
                        $hit->setPageLanguage($query['language']);
                    }

                    if (isset($query['title'])) {
                        if (!$decoded) {
                            $query['title'] = urldecode($query['title']);<commit_msg>Adds a prefix to the tracking url's page info query params with fallback to the originals to fix #649<commit_after><?php
/**
 * @package     Mautic
 * @copyright   2014 Mautic Contributors. All rights reserved.
 * @author      Mautic
 * @link        http://mautic.org
 * @license     GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */

namespace Mautic\PageBundle\Model;

use Mautic\CoreBundle\Helper\InputHelper;
use Mautic\CoreBundle\Model\FormModel;
use Mautic\PageBundle\Entity\Hit;
use Mautic\PageBundle\Entity\Page;
use Mautic\PageBundle\Entity\Redirect;
use Mautic\PageBundle\Event\PageBuilderEvent;
use Mautic\PageBundle\Event\PageEvent;
use Mautic\PageBundle\Event\PageHitEvent;
use Mautic\PageBundle\PageEvents;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;

/**
 * Class PageModel
 */
class PageModel extends FormModel
{

    /**
     * @return \Mautic\PageBundle\Entity\PageRepository
     */
    public function getRepository ()
    {
        $repo = $this->em->getRepository('MauticPageBundle:Page');
        $repo->setCurrentUser(
            $this->factory->getUser()
        );
        return $repo;
    }

    /**
     * @return \Mautic\PageBundle\Entity\HitRepository
     */
    public function getHitRepository()
    {
        return $this->em->getRepository('MauticPageBundle:Hit');
    }

    /**
     * {@inheritdoc}
     */
    public function getPermissionBase ()
    {
        return 'page:pages';
    }

    /**
     * {@inheritdoc}
     */
    public function getNameGetter ()
    {
        return 'getTitle';
    }

    /**
     * {@inheritdoc}
     *
     * @param Page $entity
     * @param bool $unlock
     */
    public function saveEntity ($entity, $unlock = true)
    {
        if (empty($this->inConversion)) {
            $alias = $entity->getAlias();
            if (empty($alias)) {
                $alias = strtolower(InputHelper::alphanum($entity->getTitle(), false, '-'));
            } else {
                $alias = strtolower(InputHelper::alphanum($alias, false, '-'));
            }

            //make sure alias is not already taken
            $repo      = $this->getRepository();
            $testAlias = $alias;
            $count     = $repo->checkUniqueAlias($testAlias, $entity);
            $aliasTag  = $count;

            while ($count) {
                $testAlias = $alias . $aliasTag;
                $count     = $repo->checkUniqueAlias($testAlias, $entity);
                $aliasTag++;
            }
            if ($testAlias != $alias) {
                $alias = $testAlias;
            }
            $entity->setAlias($alias);
        }

        $now = new \DateTime();

        //set the author for new pages
        if (!$entity->isNew()) {
            //increase the revision
            $revision = $entity->getRevision();
            $revision++;
            $entity->setRevision($revision);

            //reset the variant hit and start date if there are any changes
            $changes   = $entity->getChanges();
            $isVariant = $entity->getVariantStartDate();
            if ($isVariant !== null && !empty($changes) && empty($this->inConversion)) {
                $entity->setVariantHits(0);
                $entity->setVariantStartDate($now);
            }
        }

        parent::saveEntity($entity, $unlock);

        //also reset variants if applicable due to changes
        if (!empty($changes) && empty($this->inConversion)) {
            $parent   = $entity->getVariantParent();
            $children = (!empty($parent)) ? $parent->getVariantChildren() : $entity->getVariantChildren();

            $variants = array();
            if (!empty($parent)) {
                $parent->setVariantHits(0);
                $parent->setVariantStartDate($now);
                $variants[] = $parent;
            }

            if (count($children)) {
                foreach ($children as $child) {
                    $child->setVariantHits(0);
                    $child->setVariantStartDate($now);
                    $variants[] = $child;
                }
            }

            //if the parent was changed, then that parent/children must also be reset
            if (isset($changes['variantParent'])) {
                $parent = $this->getEntity($changes['variantParent'][0]);
                if (!empty($parent)) {
                    $parent->setVariantHits(0);
                    $parent->setVariantStartDate($now);
                    $variants[] = $parent;

                    $children = $parent->getVariantChildren();
                    if (count($children)) {
                        foreach ($children as $child) {
                            $child->setVariantHits(0);
                            $child->setVariantStartDate($now);
                            $variants[] = $child;
                        }
                    }
                }
            }

            if (!empty($variants)) {
                $this->saveEntities($variants, false);
            }
        }
    }

    /**
     * {@inheritdoc}
     *
     * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
     */
    public function createForm ($entity, $formFactory, $action = null, $options = array())
    {
        if (!$entity instanceof Page) {
            throw new MethodNotAllowedHttpException(array('Page'));
        }

        if (!isset($options['formName'])) {
            $options['formName'] = 'page';
        }

        $params = (!empty($action)) ? array('action' => $action) : array();

        return $formFactory->create($options['formName'], $entity, $params);
    }

    /**
     * {@inheritdoc}
     *
     * @return null|Page
     */
    public function getEntity ($id = null)
    {
        if ($id === null) {
            $entity = new Page();
            $entity->setSessionId('new_' . hash('sha1', uniqid(mt_rand())));
        } else {
            $entity = parent::getEntity($id);
            if ($entity !== null) {
                $entity->setSessionId($entity->getId());
            }
        }

        return $entity;
    }

    /**
     * {@inheritdoc}
     *
     * @throws \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException
     */
    protected function dispatchEvent ($action, &$entity, $isNew = false, Event $event = null)
    {
        if (!$entity instanceof Page) {
            throw new MethodNotAllowedHttpException(array('Page'));
        }

        switch ($action) {
            case 'pre_save':
                $name = PageEvents::PAGE_PRE_SAVE;
                break;
            case 'post_save':
                $name = PageEvents::PAGE_POST_SAVE;
                break;
            case 'pre_delete':
                $name = PageEvents::PAGE_PRE_DELETE;
                break;
            case 'post_delete':
                $name = PageEvents::PAGE_POST_DELETE;
                break;
            default:
                return null;
        }

        if ($this->dispatcher->hasListeners($name)) {
            if (empty($event)) {
                $event = new PageEvent($entity, $isNew);
                $event->setEntityManager($this->em);
            }

            $this->dispatcher->dispatch($name, $event);

            return $event;
        }

        return null;
    }

    /**
     * Get list of entities for autopopulate fields
     *
     * @param string $type
     * @param string $filter
     * @param int    $limit
     *
     * @return array
     */
    public function getLookupResults ($type, $filter = '', $limit = 10)
    {
        $results = array();
        switch ($type) {
            case 'page':
                $viewOther = $this->security->isGranted('page:pages:viewother');
                $repo      = $this->getRepository();
                $repo->setCurrentUser($this->factory->getUser());
                $results = $repo->getPageList($filter, $limit, 0, $viewOther);
                break;
        }

        return $results;
    }

    /**
     * Generate URL for a page
     *
     * @param Page  $entity
     * @param bool  $absolute
     * @param array $clickthrough
     *
     * @return string
     */
    public function generateUrl ($entity, $absolute = true, $clickthrough = array())
    {
        // If this is a variant, then get the parent's URL
        $parent = $entity->getVariantParent();
        if ($parent != null) {
            $entity = $parent;
        }

        $slug = $this->generateSlug($entity);

        return $this->buildUrl('mautic_page_public', array('slug' => $slug), $absolute, $clickthrough);
    }

    /**
     * Generates slug string
     *
     * @param $entity
     *
     * @return string
     */
    public function generateSlug ($entity)
    {
        $pageSlug =  $entity->getAlias();

        //should the url include the category
        $catInUrl = $this->factory->getParameter('cat_in_page_url');
        if ($catInUrl) {
            $category = $entity->getCategory();
            $catSlug  = (!empty($category)) ? $category->getAlias() :
                $this->translator->trans('mautic.core.url.uncategorized');
        }

        $parent = $entity->getTranslationParent();
        $slugs  = array();
        if ($parent) {
            //multiple languages so tack on the language
            $slugs[] = $entity->getLanguage();
        }

        if (!empty($catSlug)) {
            // Insert category slug
            $slugs[] = $catSlug;
            $slugs[] = $pageSlug;
        } else {
            // Insert just the page slug
            $slugs[] = $pageSlug;
        }

        return implode('/', $slugs);
    }

    /**
     * @param Page    $page
     * @param Request $request
     * @param string  $code
     *
     * @return void
     */
    public function hitPage ($page, $request, $code = '200')
    {
        //don't skew results with in-house hits
        if (!$this->factory->getSecurity()->isAnonymous()) {
            return;
        }

        $hitRepo = $this->getHitRepository();
        $hit = new Hit();
        $hit->setDateHit(new \Datetime());

        //check for existing IP
        $ipAddress = $this->factory->getIpAddress();
        $hit->setIpAddress($ipAddress);

        /** @var \Mautic\LeadBundle\Model\LeadModel $leadModel */
        $leadModel = $this->factory->getModel('lead');

        //check for any clickthrough info
        $clickthrough = $request->get('ct', false);
        if (!empty($clickthrough)) {
            $clickthrough = $this->decodeArrayFromUrl($clickthrough);

            if (!empty($clickthrough['lead'])) {
                $lead = $leadModel->getEntity($clickthrough['lead']);
                if ($lead !== null) {
                    $leadModel->setLeadCookie($clickthrough['lead']);
                    $leadClickthrough = true;

                    $leadModel->setCurrentLead($lead);
                }
            }

            if (!empty($clickthrough['source'])) {
                $hit->setSource($clickthrough['source'][0]);
                $hit->setSourceId($clickthrough['source'][1]);
            }

            if (!empty($clickthrough['email'])) {
                $hit->setEmail($this->em->getReference('MauticEmailBundle:Email', $clickthrough['email']));
            }
        }

        if (empty($leadClickthrough)) {
            $lead = $leadModel->getCurrentLead();
        }

        if ($page instanceof Redirect) {
            //use the configured redirect URL
            $pageURL = $page->getUrl();
        } else {
            //use current URL

            // Tracking pixel is used
            if (strpos($request->server->get('REQUEST_URI'), '/mtracking.gif') !== false) {
                $pageURL = $request->server->get('HTTP_REFERER');

                // if additional data were sent with the tracking pixel
                if ($request->server->get('QUERY_STRING')) {
                    parse_str($request->server->get('QUERY_STRING'), $query);

                    // URL attr 'd' is encoded so let's decode it first.
                    $decoded = false;
                    if (isset($query['d'])) {
                        // parse_str auto urldecodes
                        $query   = unserialize(base64_decode($query['d']));
                        $decoded = true;
                    }

                    if (isset($query['page_url'])) {
                        $pageURL = $query['page_url'];
                        if (!$decoded) {
                            $pageURL = urldecode($pageURL);
                        }
                    } elseif (isset($query['url'])) {
                        $pageURL = $query['url'];
                        if (!$decoded) {
                            $pageURL = urldecode($pageURL);
                        }
                    }

                    if (isset($query['page_referrer'])) {
                        if (!$decoded) {
                            $query['page_referrer'] = urldecode($query['page_referrer']);
                        }
                        $hit->setReferer($query['page_referrer']);
                    } elseif (isset($query['referrer'])) {
                        if (!$decoded) {
                            $query['referrer'] = urldecode($query['referrer']);
                        }
                        $hit->setReferer($query['referrer']);
                    }

                    if (isset($query['page_language'])) {
                        if (!$decoded) {
                            $query['page_language'] = urldecode($query['page_language']);
                        }
                        $hit->setPageLanguage($query['page_language']);
                    } elseif (isset($query['language'])) {
                        if (!$decoded) {
                            $query['language'] = urldecode($query['language']);
                        }
                        $hit->setPageLanguage($query['language']);
                    }

                    if (isset($query['page_title'])) {
                        if (!$decoded) {
                            $query['page_title'] = urldecode($query['page_title']);
                        }
                        $hit->setUrlTitle($query['page_title']);
                    } elseif (isset($query['title'])) {
                        if (!$decoded) {
                            $query['title'] = urldecode($query['title']);
{'fraction_non_alphanumeric': 0.14083441418071768, 'fraction_numerical': 0.0018374405533938608, 'mean_word_length': 1.567952632065871, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 206, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2354985', 'n_tokens_mistral': 7562, 'n_tokens_neox': 7251, 'n_words': 1436}