Showing posts with label symfony2. Show all posts
Showing posts with label symfony2. Show all posts

Monday, January 23, 2017

“AH01071: Got error 'Unable to open primary script”: Container permissions or Symfony3 issue?

Leave a Comment

I am trying to run a Symfony 3 "base" application (meaning non complexity at all and just a few bundles installed but not even enabled) in a "LAMP" stack using Docker and Docker Compose (I've removed MySQL from the post because it's not relevant). This is my docker-compose.yml file:

version: '2' services:   php-fpm:     build: docker/php-fpm     ports:         - "80:80"     volumes:       - ./sources:/data/www       - ./data/logs/symfony:/data/www/var/logs   db:     image: mysql     environment:         MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}         MYSQL_DATABASE: ${MYSQL_DATABASE}         MYSQL_USER: ${MYSQL_USER}         MYSQL_PASSWORD: ${MYSQL_PASSWORD}     volumes:         - sql-data:/var/lib/mysql 

And this is the Dockerfile for the php-fpm container:

FROM reynierpm/docker-centos7-supervisord:latest ENV TERM=xterm \     PATH="/root/.composer/vendor/bin:${PATH}" \     COMPOSER_ALLOW_SUPERUSER=1 RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \                    https://rpms.remirepo.net/enterprise/remi-release-7.rpm RUN yum install -y  \         yum-utils \         git \         zip \         unzip \         nano \         httpd \         php71-php-fpm \         php71-php-cli \         php71-php-common \         php71-php-gd \         php71-php-intl \         php71-php-json \         php71-php-mbstring \         php71-php-mcrypt \         php71-php-mysqlnd \         php71-php-pdo \         php71-php-pear \         php71-php-xml \         php71-pecl-apcu \         php71-php-pecl-apfd \         php71-php-pecl-memcache \         php71-php-pecl-memcached \         php71-php-pecl-mongodb \         php71-php-pecl-redis \         php71-php-pecl-request \         php71-php-pecl-uploadprogress \         php71-php-pecl-xattr \         php71-php-pecl-zip && \         yum clean all && rm -rf /tmp/yum*  RUN rm -f /etc/httpd/conf/httpd.conf /etc/httpd/conf.d/* /etc/httpd/conf.modules.d/* && \     ln -sfF /opt/remi/php71/enable /etc/profile.d/php71-paths.sh && \     ln -sfF /opt/remi/php71/root/usr/bin/{pear,pecl,phar,php,php-cgi,phpize} /usr/local/bin/. && \     mv -f /etc/opt/remi/php71/php.ini /etc/php.ini && \     ln -s /etc/php.ini /etc/opt/remi/php71/php.ini && \     rm -rf /etc/php.d && \     mv /etc/opt/remi/php71/php.d /etc/. && \     ln -s /etc/php.d /etc/opt/remi/php71/php.d  RUN curl -LsS https://symfony.com/installer -o /usr/local/bin/symfony && \     chmod a+x /usr/local/bin/symfony  COPY container-files /  RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && \     composer global install --no-dev  RUN yum install -y php71-php-pecl-xdebug && \     yum clean all && rm -rf /tmp/yum* && \     php --version  RUN chmod +x /config/bootstrap.sh RUN echo 'alias sf="php bin/console"' >> ~/.bashrc  WORKDIR /data/www EXPOSE 80 9001 

The thing is I am getting this error all the time if I try to access the dev environment using http://symfonyapp.local/app_dev.php:

php-fpm  | [Sat Jan 14 15:09:27.655609 2017] [proxy_fcgi:error] [pid 13:tid 140600250660608] [client 172.18.0.1:43960] AH01071: Got error 'Unable to open primary script: /data/www/web/_wdt/210673 (No such file or directory)\n', referer: http://symfonyapp.local/app_dev.php 

Having the error above I can think in:

  • Ownership|permissions issue at /data/www/web in the container which is odd since that folder is owned by root and well .... is root I don't need to explain
  • Something is failing with Symfony3 and I'm not aware of it also I couldn't find it so far
  • Apache|PHP-FPM can't write on such folder which leads to the first item on this list
  • Apache config is blocking the directory /web to be written. (mod_scurity is not running so I can't blame it)

This is what I've tried so far without success because I am still getting the same error all the time.

  1. Change ownership/permissions in the container (this lead into an error in Linux since permissions in volumes are changed in host as well, the same doesn't happen in Windows). Below is an explanation in how do I achieve such thing.

Brief explanation in how do I change ownership/permissions:

The php-fpm Dockerfile is inherit from docker-centos7-supervisord which has this script as ENTRYPOINT. So I have created a file /container-files/config/init/20-permissions.sh with the following content:

#!/usr/bin/env bash  chown -R apache:root /data/www && \ find /data/www -type d -print0 | xargs -0 chmod 775 && \ find /data/www -type f -print0 | xargs -0 chmod 664 echo "Set up permissions finished"  exec "$@" 

The file above gets executed after container starts and volumes are mounted. I did know the file is executed because I am seeing Set up permissions finished in the php-fpm container logs. It's weird though because checking ownership/permissions after show me the following:

> docker exec -it php-fpm ls -la /data/www/web total 57 drwxr-xr-x 2 root root  4096 Jan 14 03:45 . drwxr-xr-x 2 root root  4096 Jan 14 00:40 .. -rwxr-xr-x 1 root root  3319 Jan 13 23:54 .htaccess -rwxr-xr-x 1 root root   635 Jan 14 03:45 app.php -rwxr-xr-x 1 root root  1184 Jan 14 03:45 app_dev.php -rwxr-xr-x 1 root root  2092 Jan 13 23:54 apple-touch-icon.png drwxr-xr-x 2 root root     0 Dec 13 13:36 bundles -rwxr-xr-x 1 root root 21244 Jan 14 00:04 config.php -rwxr-xr-x 1 root root  6518 Jan 13 23:54 favicon.ico -rwxr-xr-x 1 root root   116 Jan 13 23:54 robots.txt 

So in this case I am not sure if this is going well or if it's possible even. I have created a repository with two branches with all the necessary to gives this a try: master having httpd and php-fpm both in one container and httpd having them in separated containers. Although the result in both is the same.

To get everything up and running you should:

  • Run docker-compose up -d --build --force-recreate (the --force-recreate and --build are not necessary but is just in case)
  • Run docker exec -it php-fpm composer update so you download the libraries needed by the project.
  • Add symfonyapp.local to your hosts files

Currently I am using Docker in Windows, this is the info about it:

Version: 1.13.0-rc6-beta36 (9696) Channel: Beta Sha1: 64a715b54327a0ec8f28076d1a343f4c811856fb Started on: 2017/01/13 18:34:34.519 Resources: C:\Program Files\Docker\Docker\Resources OS: Windows 10 Pro Edition: Professional Id: 1607 Build: 14393 BuildLabName: 14393.693.amd64fre.rs1_release.161220-1747 

But I have tested this in Linux as well and I have the same behavior meaning the error still there.

What is happening here? Can you give me some ideas or solution? At this point I am out of them and don't know what else to do.

2 Answers

Answers 1

TL;DR: The permission problem is being introduced during composer update. Possibly during one of the scripts (a list of which can be found in composer.json).

I started from scratch on a VM with your repository and followed your startup instructions.

git clone https://github.com/reypm/symfony3app cd symfony3app docker-compose up -d --build --force-recreate 

At this point, the chown from 20-permissions.sh should have been run. To verify that, I looked inside the container. The error I have seen related to /data/www/var/cache/dev, so I looked at the permissions on every directory in that path.

[my-vm]# docker-compose exec php-fpm bash [container]# ls -la /data/www{,/var{,/cache{,/dev}}}  ls: cannot access /data/www/var/cache/dev: No such file or directory /data/www: total 168 drwxrwsr-x 8 apache root   4096 Jan 15 19:26 . drwxr-xr-x 8 root   root   4096 Jan 15 19:27 .. -rw-rw-r-- 1 apache root    248 Jan 15 19:26 .gitignore -rw-rw-r-- 1 apache root     74 Jan 15 19:26 README.md drwxrwsr-x 5 apache root   4096 Jan 15 19:27 app drwxrwsr-x 2 apache root   4096 Jan 15 19:26 bin -rw-rw-r-- 1 apache root   2387 Jan 15 19:26 composer.json -rw-rw-r-- 1 apache root 119533 Jan 15 19:26 composer.lock -rw-rw-r-- 1 apache root    978 Jan 15 19:26 phpunit.xml.dist drwxrwsr-x 3 apache root   4096 Jan 15 19:26 src drwxrwsr-x 3 apache root   4096 Jan 15 19:26 tests drwxrwsr-x 4 apache root   4096 Jan 15 19:26 var drwxrwsr-x 2 apache root   4096 Jan 15 19:26 web  /data/www/var: total 52 drwxrwsr-x 4 apache root  4096 Jan 15 19:26 . drwxrwsr-x 8 apache root  4096 Jan 15 19:26 .. -rw-rw-r-- 1 apache root 34272 Jan 15 19:26 SymfonyRequirements.php drwxrwsr-x 2 apache root  4096 Jan 15 19:26 cache drwxrwsr-x 2 apache root  4096 Jan 15 19:26 sessions  /data/www/var/cache: total 8 drwxrwsr-x 2 apache root 4096 Jan 15 19:26 . drwxrwsr-x 4 apache root 4096 Jan 15 19:26 .. -rw-rw-r-- 1 apache root    0 Jan 15 19:26 .gitkeep 

So far, so good. The chown has set everything to apache:root and using the modes specified in the script.

Next, I exited the container and ran the composer update.

docker-compose exec php-fpm composer update 

When prompted, I used the database parameters I found in the git repo, and everything installed fine. Next, I went back into the container to see if the permissions had changed.

[my-vm]# docker-compose exec php-fpm bash [container]# ls -la /data/www{,/var{,/cache{,/dev}}}  /data/www: total 164 drwxrwsr-x  9 apache root   4096 Jan 15 19:20 . drwxr-xr-x  8 root   root   4096 Jan 15 19:18 .. -rw-rw-r--  1 apache root    248 Jan 15 19:17 .gitignore -rw-rw-r--  1 apache root     74 Jan 15 19:17 README.md drwxrwsr-x  5 apache root   4096 Jan 15 19:18 app drwxrwsr-x  2 apache root   4096 Jan 15 19:21 bin -rw-rw-r--  1 apache root   2387 Jan 15 19:17 composer.json -rw-rw-r--  1 apache root 114331 Jan 15 19:20 composer.lock -rw-rw-r--  1 apache root    978 Jan 15 19:17 phpunit.xml.dist drwxrwsr-x  3 apache root   4096 Jan 15 19:17 src drwxrwsr-x  3 apache root   4096 Jan 15 19:17 tests drwxrwsr-x  5 apache root   4096 Jan 15 19:21 var drwxr-sr-x 25 root   root   4096 Jan 15 19:21 vendor drwxrwsr-x  3 apache root   4096 Jan 15 19:21 web  /data/www/var: total 96 drwxrwsr-x 5 apache root  4096 Jan 15 19:21 . drwxrwsr-x 9 apache root  4096 Jan 15 19:20 .. -rw-rw-r-- 1 apache root 34272 Jan 15 19:21 SymfonyRequirements.php -rw-r--r-- 1 root   root 39637 Jan 15 19:21 bootstrap.php.cache drwxrwsr-x 3 apache root  4096 Jan 15 19:21 cache drwxr-sr-x 2 root   root  4096 Jan 15 19:21 logs drwxrwsr-x 2 apache root  4096 Jan 15 19:17 sessions  /data/www/var/cache: total 12 drwxrwsr-x 3 apache root 4096 Jan 15 19:21 . drwxrwsr-x 5 apache root 4096 Jan 15 19:21 .. -rw-rw-r-- 1 apache root    0 Jan 15 19:17 .gitkeep drwxr-sr-x 4 root   root 4096 Jan 15 19:21 dev  /data/www/var/cache/dev: total 636 drwxr-sr-x 4 root   root   4096 Jan 15 19:21 . drwxrwsr-x 3 apache root   4096 Jan 15 19:21 .. -rw-r--r-- 1 root   root     90 Jan 15 19:21 annotations.map -rw-r--r-- 1 root   root 277718 Jan 15 19:21 appDevDebugProjectContainer.php -rw-r--r-- 1 root   root  38062 Jan 15 19:21 appDevDebugProjectContainer.php.meta -rw-r--r-- 1 root   root 213247 Jan 15 19:21 appDevDebugProjectContainer.xml -rw-r--r-- 1 root   root  84170 Jan 15 19:21 appDevDebugProjectContainerCompiler.log -rw-r--r-- 1 root   root   4790 Jan 15 19:21 classes.map drwxr-sr-x 3 root   root   4096 Jan 15 19:21 doctrine drwxr-sr-x 4 root   root   4096 Jan 15 19:21 pools 

As you can see, some things are now owned by root:root. As far as I can tell, this is simply because the container itself runs things as root. So when you exec a job inside, that job is run as root. Therefore, anything it creates is, by default, owned by root.

Meanwhile, Apache runs as the user "apache", because that is what supervisord is configured to do.

There are probably more elegant fixes for this problem, but this one was the simplest one I came up with:

docker-compose exec php-fpm chown -R apache:root /data/www/var/cache docker-compose restart php-fpm 

After that, the app returns

Welcome to Symfony 3.2.2

Your application is now ready. You can start working on it at: /data/www/

I haven't tried to fix things any better than this. But my suggestion would be to try to have the startup run composer update for you and do the chown job after that. You probably don't need to chown all of /data/www, as Apache probably doesn't need write privs to everything in there. My guess was that the cache directory is one place it needs to write, so I chown'd that path.

Answers 2

After spent days and hours trying to get this working I finally got it thanks to Symfony #support channel in Slack and to the following channels on the IRC #symfony, #httpd, #php, #docker and last but not least to @DanLowe who takes the time to find a solution and help me out with the issue.

The facts|thoughts:

  • Is a Symfony 3.2.2 issue ... is not
  • Is a Docker running on Windows ... is not
  • Is a permission issue on the directory /web ... is not
  • Is a PHP-FPM problem ... is not
  • Is a Apache (httpd) problem ... is not

The problem: A miss configuration in PHP (.ini file) due to a copy & paste from Nginx setup to be used with Apache (previously I was using Nginx and then I moved to Apache leaving the PHP setup as it was).

// this work in Nginx but does not work in Apache   // cgi.fix_pathinfo is required to get PHP to adhere to the CGI spec  ; Fix the cgi.fix_pathinfo directive cgi.fix_pathinfo = 0 

By default that line is commented in the php.ini file. But waits this could be an issue when PHP is using FastCGI and ProxyPass and so on .... well yes (I read it somewhere before) and no (if you research and set up your server as it should be). The solution to the problem above is comment out the line as it's by default:

; Fix the cgi.fix_pathinfo directive ; cgi.fix_pathinfo = 0 

The solution to the "security" breach introduced above is and I've quoted from here:

If you have a recent version of PHP-FPM (~5.3.9+?), then you need to do nothing, as the safe behaviour below is already the default.

Otherwise, find php-fpm's www.conf file (maybe /etc/php-fpm.d/www.conf, depends on your system). Make sure you have this:

security.limit_extensions = .php

Again, that's default in many places these days.

In my case I am using PHP 7.1 but even though I've secured my server by adding such line at my /etc/php-fpm.d/www.conf.

Read More

Monday, August 15, 2016

symfony 3 Too Many Redirects when forcing https

Leave a Comment

I have a problem that is similar to other question posted on SO, but none of those solutions have worked.

I'm using Apache built into OSX El Capitan Server, and https works fine when I don't force http traffic onto https via the following directive:

    access_control:     - { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https, host: mypc\.local$ } 

But adding this results in the Too Many Redirects error when visiting the local uri for my website is: https://mypc.local/myproject/web/

full security.yml:

security:   access_control:     - { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https, host: mypc\.local$ }    providers:     our_db_provider:         entity:             class: AppBundle:Users             property: username    encoders:     AppBundle\Entity\Users: plaintext     firewalls:     # disable authentication for assets and the profiler      dev:         pattern: ^/(_(profiler|wdt)|css|images|js)/         security: false      main:         pattern:    ^/         http_basic: ~         provider: our_db_provider          anonymous: ~         form_login:             login_path: /             check_path: login          logout:             path:   /logout             target: /             invalidate_session: true  

EDIT: here are the response headers:

> GET /myproject/web/ HTTP/1.1 > Host: mypc.local > User-Agent: curl/7.43.0 > Accept: */* >  < HTTP/1.1 301 Moved Permanently < Date: Tue, 09 Aug 2016 12:15:00 GMT < Server: Apache < X-Powered-By: PHP/5.5.31 < Cache-Control: no-cache < Location: https://mypc.local/myproject/web/ < MS-Author-Via: DAV < Content-Length: 396 < Content-Type: text/html; charset=UTF-8 <  * Ignoring the response-body * Connection #0 to host mypc.local left intact * Issue another request to this URL: 'https://mypc.local/myproject/web/' * Found bundle for host mypc.local: 0x7f89b2d01780 * Re-using existing connection! (#0) with host mypc.local * Connected to mypc.local (fe80::ea06:88ff:fecf:61c6) port 443 (#0) > GET /myproject/web/ HTTP/1.1 .... repeated 20 times 

0 Answers

Read More

Saturday, July 2, 2016

How to read Zend2 session in Symfony3 application

Leave a Comment

I have two applications. One the legacy one is written in Zend Framework and a new one in Symfony 3.1 should share session with an old one.

In old application native file storage is used so when I go to app_dev.php and I write session_start(); var_dump($_SESSION); I see '__ZF' key in the session and I need to get access to it in symfony3 application.

Obviously code above was only to check if session is shared within domain.

In symfony3 app I've tried to subcribe the event KernelEvents::REQUEST and there I wanted get raw session from the request and create a bag with parameters that come from Zend2.

class SessionSubscriber implements EventSubscriberInterface {     public function onKernelRequest(GetResponseEvent $event)     {          if ($event->isMasterRequest() && true == $event->getRequest()->hasSession()) {             var_dump($event->getRequest());             $event->getRequest()->getSession()->registerBag(new ZendSessionBag());             var_dump($event->getRequest()->getSession()->getBag('zf'));             exit;             return;         }     }     public static function getSubscribedEvents()     {         return array(             KernelEvents::REQUEST => (array('onKernelRequest', 127))         );     } } 

But I don't have access to raw session data from $event->getRequest();

This is how my bag looks so far. From what I understand I should have access to raw session data in initialize() method

class ZendSessionBag implements SessionBagInterface {     private $storageKey;     private $sessionData;       public function __construct($storageKey = '__ZF')     {         $this->storageKey = $storageKey;     }      public function getName()     {         return 'zf';     }      public function initialize(array &$array)     {         var_dump($array); // here should be raw $_SESSION data         $this->sessionData = &$array;     }      public function getStorageKey()     {         return $this->storageKey;     }      public function clear()     {         $this->sessionData = [];     } } 

So when I get the session and then get bag named "zf" I will have access to the data.

This is also my config regarding sessions:

session:         storage_id: session.storage.php_bridge         handler_id:  session.handler.native_file         save_path:   "/var/lib/php5/sessions" 

Any help would be appreciated.

1 Answers

Answers 1

I've managed to make it work.

Firstly I've changed configuration:

I've changed save path and remove native handler:

session:         save_path:   "/var/lib/php5/sessions" 

Then I've changed EventSubscriber:

class SessionSubscriber implements EventSubscriberInterface {     /**      * @param GetResponseEvent $event      */     public function onKernelRequest(GetResponseEvent $event)     {         $bag = null;         $session = $event->getRequest()->getSession();          try         {             $bag = $session->getBag('zf');         }         catch (\InvalidArgumentException $e)         {             $bag = new NamespacedAttributeBag("__ZF");             $bag->setName("zf");             $session->registerBag($bag);              $session->start();         }         $bag->set('userId', isset($_SESSION['Zend_Auth']->storage) ? $_SESSION['Zend_Auth']->storage : null);     }      /**      * @return array      */     public static function getSubscribedEvents()     {         return array(             KernelEvents::REQUEST => (array('onKernelRequest', 127))         );     } } 

I've imported class from Zend Zend\Stdlib\ArrayObject after that I have access to variable I want in bag zf.

Read More

Friday, June 10, 2016

Create form for Uploadable Doctrine Extension

Leave a Comment

I'd like to use Uploadable to save some images (i.e. profile picture for users). I'm using many other Doctrine Extensions already (softdeletable, timestampable, blameable, etc.) so I thought it would be nice to use this one as well.

However, I don't know how to set up my Forms. The StofDoctrineExtensionsBundle documentation gives this example:

$document = new Document(); $form = $this->createFormBuilder($document)     ->add('name')     ->add('myFile')     ->getForm() ;  //(...)  $uploadableManager->markEntityToUpload($document, $document->getMyFile()); 

In this example, is name the name of the Document or the name of the file?

Atlantic18/DoctrineExtensions's documentation adds a path, name, mimeType and size to an entity, to there is no myFile attribute.

Can anybody explain how to set up a Form for a Uploadable Doctrine entity? I couldn't find any documentation or good example that helped me further.

1 Answers

Answers 1

Entity

Like you've discovered, the documentation of DoctrineExtensions itself sheds some light on how to configure the Uploadable extension to use your entity.

Mainly by adding the @Gedmo\Uploadable annotation to your entity and @Gedmo\UploadableFilePath to the property that will contain the file path ($filePath for example).

Form

With the ->add() method of the form-builder you add fields to the form. The first parameter specifies the property-name of the corresponding entity. So ->add('myFile') would add a field for the property $myFile.

What you need to do is add a (file) field to the form for the property that will contain the file path ($filePath for example), and mark that property:

$form = $this->createFormBuilder($entity)     ->add('filePath');  $uploadableManager->markEntityToUpload($entity, $entity->getFilePath()); 

In other words: myFile in your example should be replaced with filePath in my example, and whatever the actual property is in your real code.

Read More

Thursday, May 5, 2016

Using Doctrine and Symfony to create Polymorphic like associations

Leave a Comment

I'm attempting to have an Fileable trait that will give provide an Entity with methods to CRUD Files based on the File Entity mentioned below.

After reading the documentation on Doctrine and searching the internet, the best I could find is Inheritance Mapping but these all require the subclass to extend the superclass which is not ideal as the current Entities already extend other classes. I could have FileFoo entity and a FileBar entity but this gets too messy and requires an extra join (super -> sub -> entity).

Alternatively, I could have a File Entity which has many columns for Entities (so foo_id for the Foo object, bar_id for the bar object and so on) but this gets messy and would require a new column for every entity that I'd want to add the Fileable trait too.

So to the questions: Am I thinking about how I want to hold data incorrectly? Is there some features/functions in Doctrine/Symfony that I've missed? Do you think I feature like this would be added if I were to fork Doctrine to add this feature, also where should I look?

<?php /**  * File  *  * @ORM\Table()  * @ORM\Entity()  * @ORM\HasLifecycleCallbacks()  */ class File {     /**      * @var integer      *      * @ORM\Column(type="integer")      * @ORM\Id()      * @ORM\GeneratedValue()      */     protected $id;     /**      * @var string      *      * @ORM\Column(type="string")      */     protected $entityName;     /**      * @var string      *      * @ORM\Column(type="string")      */     protected $entityId; ... 

2 Answers

Answers 1

I accomplished a similar thing using Inheritance defined in traits, which alongside interfaces, basically gave me what a multiple extend would give.

Answers 2

Take a look at embeddables or you could use traits.

Read More

Tuesday, March 29, 2016

Testing Abstract Document Repository which interacts with MongoDB

Leave a Comment

Heey all,

I'm having troubles to set up a testcase. I have a plain symfony 3 project connected to mongodb. I have multiple documents which each needs an extra method to query the database. The method will get the last document inserted in the collection and is called findLatestInserted().

This specific function was duplicated in each document repository. So I decided to extract it and create a class BaseDocumentRepository which extends the default DocumentRepository. All of my document repositories still have their own DocumentRepository class let's say: CpuInfoRepository, RamInfoRepository. These classes do offer a few extra methods to query the mongodb database and the one in common: findLatestInserted()

It all works fine but just in case i'd wanted to write a unit test for this method findLatestInserted().

I have a test database called prototyping-test which is used to create a document and query it and check the result. Afterwards it'll clear itself so no documents stays in. For each repository there's a specific url to post data to to create a file in the database. To create a CpuInfo collection you'll post data to http://localhost:8000/ServerInfo/CreateCpuInfo. To create a RamInfo collection you'll post data to http://localhost:8000/ServerInfo/CreateRamInfo.

So here follows my question how would i write a test to test the method findLatestInserted()?

this is what i've tried so far:

public function testFindLatestInserted() {     $client = self::createClient();     $crawler = $client->request('POST',         '/ServerInfo/CreateCpuInfo',         [             "hostname" => $this->hostname,             "timestamp" => $this->timestamp,             "cpuCores" => $this->cpuCores,             "cpu1" => $this->cpu1,             "cpu2" => $this->cpu2         ]);     $this->assertTrue($client->getResponse()->isSuccessful());      $serializer = $this->container->get('jms_serializer');     $cpuInfo = $serializer->deserialize($client->getResponse()->getContent(), 'AppBundle\Document\CpuInfo', 'json');      $expected = $this->dm->getRepository("AppBundle:CpuInfo")->find($cpuInfo->getId());     $stub = $this->getMockForAbstractClass('BaseDocumentRepository');      $actual = $this->dm         ->getRepository('AppBundle:CpuInfo')         ->findLatestInserted();      $this->assertNotNull($actual);     $this->assertEquals($expected, $actual); } 

At the line $actual = $this->dm->getRepository('AppBundle:CpuInfo')->findLatestInserted(); i got stuck. As this would only test for CpuInfo while there is RamInfo too (and some other classes not mentioned here). How would one approach this setting? I specificly want to test the method findLatestInserted() on the level of the abstract class instead of the concrete classes.

Please help me out!

1 Answers

Answers 1

Instead of testing the whole stack, just concentrate on testing findLatestInserted() in concrete classes.

Inject MondoDB stub into AppBundle:CpuInfo and check if findLatestInserted() returns expected value. Do the same for AppBundle:RamInfo.

Avoid testing abstract classes, always test concrete classes. In future, you may decide not to inherit from BaseDocumentRepository and may not notice that new implementation of findLatestInserted() fails.

Read More

Monday, March 28, 2016

Doctrine 2 Symfony 2 Getting foreign key entities without mapping

Leave a Comment

so I am fairly new to Symfony and Doctrine. I would like to know if there's a way to ask doctrine what foreign keys are in place, but without having to map relationships in the model.

For example, say you have CoreBundle:Company which is ALWAYS going to be present, and then you have OptionalBundle:Client which will extend Company with a @OneToOne mapping relationship, adding a few more fields in itself. The thing is, that since OptionalBundle may not be present, I don't want explicit mapping from CoreBundle to OptionalBundle.

Now say a user comes along and attempts to delete Company(5). If the entity was fully mapped it would delete both with cascading, but since the bundle is not going to be aware of a mapped relationship it would end up deleting the Company only - I want to produce an error rather than cascading the deletion.

If this is possible quite easily, then I would also want to take it another step further and say, what entities (class and id) have foreign keys that I can show the data to the user, like

@CoreBundle:Company(5) ->     has @OptionalBundle:Client(3) linked, and     has @AnotherOptionalBundle:Supplier(12) linked 

My first instinct is to do a custom INFORMATION_SCHEMA lookup for the foreign keys but that will only give me table names...

PS I REALLY prefer not to have to use any third party vendors as I like to try and keep the dependencies down, even if it means reinventing the wheel

3 Answers

Answers 1

Have you considered defining the relationship as owned by the OptionalBundle side?

Answers 2

The only idea I come across is to pre-create class-mapping during Compiler Pass with some fallback type when secondary bundle is absent.

In compiler pass, check whether container has a secondary bundle loaded and use DoctrineOrmMappingsPass::createXmlMappingDriver with adjusted path. If found - map with secondary bundle's entity, if not - map it to null (for example).

Answers 3

Question 1

You could set the Client as the owner of the 1-to-1 relationship. However, depending on your use-case it might not be ideal, but if that works for you it would really be the simplest solution, as pointed out by ABM_Dan.

Barring that, the best option for you is probably to use Doctrine event subscribers and to hook on the preDelete event, where you would remove the associated Client, before the Company itself is removed - if cascading the deletion is really what you want.

By default both deletion will be in the same Doctrine transaction, meaning that if something goes wrong when deleting the Company, the Client deletion will be cancelled.

If you really want to trigger an error instead of this "manual cascading" of sorts, it is also possible in the preDelete method of the Doctrine subscriber.

The subscriber class can reside in your optional bundle even though it will act on an event associated to Company.

Doctrine event subscribers are separate from the regular Symfony event system. Newcomers often are not aware of its existence, but it can achieve a lot of interesting things.

Question 2

Still in your event subscribers, it is possible to hook on the postLoad event. This would allow you to request the database and load related entities directly into Company. You can create an event subscriber for Company in each bundle that requires it.

Although this is possible I really wonder if there might not be a better way. Using decorators might be a better solution. I found a Doctrine cookbook article about it.

Read More

Tuesday, March 8, 2016

Running Symfony2 on ISPConfig3

Leave a Comment

The whole ISPConfig installation, configuration and all that is involved have been a tough road. With bumps and bruises I've finally got the complete package running the way I want it to.

Those bumps and bruises are probably because I am inexperienced with Linux (Debian Wheezy).

However, now everything is set up, I have come to the point of installing Symfony2. This, like all other aspects of ISPConfig, doesn't go as it is supposed to go.

My issues:

  • I don't know how to configure nginx for symfony2 from the Web GUI
  • When running symfony it doesn't redirect to app.php
  • When i go directly to app.php it throws me a 500

The logs tell me there is a problem with the app directory not being accesible by open_basedir().

What I am actually looking for is a little guidence in how to configure this whole thing.

Feel free to ask for additional information. I will gladly update my question.

Thanks in advance.

Nginx site conf

server {         listen ...:80;          listen ...:443 ssl;         ssl_protocols ...         ssl_certificate ...         ssl_certificate_key ...;          server_name mydomain.tld;          root   /var/www/mydomain.tld/web;            index index.html index.htm index.php index.cgi index.pl index.xhtml;           location ~ \.shtml$ {             ssi on;         }           error_page 400 /error/400.html;         error_page 401 /error/401.html;         error_page 403 /error/403.html;         error_page 404 /error/404.html;         error_page 405 /error/405.html;         error_page 500 /error/500.html;         error_page 502 /error/502.html;         error_page 503 /error/503.html;         recursive_error_pages on;         location = /error/400.html {              internal;         }         location = /error/401.html {              internal;         }         location = /error/403.html {              internal;         }         location = /error/404.html {              internal;         }         location = /error/405.html {              internal;         }         location = /error/500.html {              internal;         }         location = /error/502.html {              internal;         }         location = /error/503.html {              internal;         }          error_log /var/log/ispconfig/httpd/mydomain.tld/error.log;         access_log /var/log/ispconfig/httpd/mydomain.tld/access.log combined;          location ~ /\. {             deny all;             access_log off;             log_not_found off;         }          location = /favicon.ico {             log_not_found off;             access_log off;         }          location = /robots.txt {             allow all;             log_not_found off;             access_log off;         }          location @php {             try_files $uri =404;             include /etc/nginx/fastcgi_params;             fastcgi_pass unix:/var/lib/php5-fpm/web3.sock;             fastcgi_index index.php;             fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;             fastcgi_intercept_errors on;         }  } 

I would like to note that this configuration is automatically generated by ISPConfig and that this should probably be edited from the Web GUI.

Edit

I have fixed the internal server error by adding all symfony folders to:

ISPConfig Web > Sites > mydomain.tld > Options > PHP open_basedir 

1 Answers

Answers 1

The configuration is missing the actual relaying to PHP. It should work if you exchange the location @php block with the following three blocks:

location / {   try_files $uri @php; }  location app.php {   try_files @php =404; }  location @php {     include /etc/nginx/fastcgi_params;     fastcgi_pass unix:/var/lib/php5-fpm/web3.sock;     fastcgi_param  SCRIPT_NAME  app.php;     fastcgi_param  SCRIPT_FILENAME  app.php;     fastcgi_intercept_errors on; } 

The first block tries to find the requested file in the given root directory, meaning /var/www/mydomain.tld/web - now all Symfony assets will work and be returned, because they are all in the web directory. If the file is not found, it calls PHP.

The second block is used if /app.php is requested directly - instead of delivering that file, we process it with PHP.

The third block configures PHP - the previous two blocks always refer to this block, so any file not directly found is processed by PHP. Symfony only has one front controller, app.php, so we just send all requests to that entry point.

With this setup, it should be quite secure, because only app.php is ever processed by PHP. For a testing environment, you can use app_dev.php instead of app.php (just change the filename in the @php block) - but never for production and without securing the testing environment.

Read More